• IIC总线


    我这块板子很多芯片都是IIC总线传输,所以先去学了下IIC,然后继续操作芯片。(初学者经验不足,在淘宝上看他们给的截图包含大量的视频,实际结果是只有简单的实验有教程,其他的直接给代码,悲哀啊!!!)

    网上可以很容易找到IIC总线的中文资料,我这里就不在啰嗦,我简单的把IIC的操作封装下,方便使用。

    1、D/A实验:

    (D/A芯片是 PCF8591,目的是控制LED灯缓慢熄灭)

    #include "iic.h"      // 引入IIC操作,自定义的库
    #include <reg52.h>
    
    void main()
    {    
        uchar num;
        IIC_INIT();   // 初始化IIC总线
    
        while(1)
        {
            write_byte(0x90,0x40,num);   // 0x90 为PCF8591地址,0x40 为控制命令, num 为转换数据
            num ++;
            delay(20);
        }
    }

    2、EEPROM实验

    (EEPROM芯片采用 AT24C02A,目的是向芯片内部某一个地址写入一个字节,然后读出该数据送给8个发光二极管)

    #include "iic.h"
    #include <reg52.h>
    
    void main()
    {    
        IIC_INIT();     // 初始化IIC总线
    
        write_byte(0xa0,10,0x55);  // 向芯片地址10,写入数据0x55
        delay(20);                 // 延时20ms
        P1 = read_byte(0xa1,10);   // 从芯片地址10,读出数据并送入P1口,P1接了8个发光二极管
        while(1);
    }

    主程序写起来非常简单,所有操作都封装在iic.c中

    IIC.h

    #ifndef __IIC_H__
    #define __IIC_H__
    #include "delay.h"
    
    void IIC_INIT();     // 器件初始化
    void write_byte(uchar add,uchar command1,uchar command2);  // 写一个字节
    uchar read_byte(uchar add,uchar command1);                 // 读一个字节
    
    #endif
    
    // IIC_INIT();
    // write_byte(add,command1,command2);
    // temp = read_byte(add,command1);

    IIC.c

    #include <reg52.h>
    #include "IIC.h"
    
    
    void extra();    // 我这个板子必须调用,因为有干扰
    void start();    // IIC 启动信号
    void stop();    // IIC 停止信号
    void ack();        // IIC 应答信号
    void noack();    // IIC 非应答信号
    void iicwr_byte(uchar);     // IIC 写一个字节
    uchar iicre_byte();         // IIC 读一个字节
    
    
    
    sbit RST=P2^5;   //时钟  不需要,可以关掉
    sbit CS_DA =P2^4 ;  //可以关掉
    sbit sda = P2^0;       // 两个控制端
    sbit scl = P2^1;       // 两个控制端
    
    void extra()    // 这个函数我的板子必须用,因为会影响我的实验
    {
        RST=0; //总线时钟低电评
        CS_DA =0;     
    }
    
    void IIC_INIT()
    {    
        extra();
        sda = 1;   
        scl = 1;
    }
    
    void iicwr_byte(uchar dat)
    {
        uchar i;
        scl = 0;
        for (i = 0;i < 8;i ++)
        {
            if (dat & 0x80)
            {
                sda = 1;
            }else{
                sda = 0;
            }
            dat = dat << 1;
            delay_us(5);
            scl = 1;
            delay_us(5);
            scl = 0;
            delay_us(5);
        }
        sda = 1;
        delay_us(5);    
    }
    
    uchar iicre_byte()
    {
        uchar i,dat;
        scl = 0;
        delay_us(5);
        sda = 1;      // 释放数据总线,以便器件回传数据,一旦为低电平,由于线与关系,将无法操作
        delay_us(5);
        for (i = 0;i < 8;i ++)
        {
            scl = 1;
            delay_us(5);
            dat <<= 1;
            if (sda)
            {
                dat ++;    
            }
            scl = 0;
            delay_us(5);
        }
        return dat;
    }
    
    void start()  // 起始信号
    {
        sda = 1;
        delay_us(5);
        scl = 1;
        delay_us(5);
        sda = 0;
        delay_us(5);    
    }
    
    void stop()   // 停止信号
    {
        sda = 0;
        delay_us(5);
        scl = 1;
        delay_us(5);
        sda = 1;
        delay_us(5);        
    }
    
    void ack()   // 应答
    {
        uchar i;
        scl = 1;
        delay_us(5);
        while((sda == 1) && (i < 200)) i++;  // 等待应答信号一定时间
        scl = 0;
        delay_us(5);
    }
    
    void noack()   // 非应答
    {
        sda = 1;
        delay_us(5);
        scl = 1;
        delay_us(5);
        scl = 0;
        delay_us(5);
    }
    
    uchar read_byte(uchar add,uchar command1)
    {
        uchar temp;
        uchar tt = add & 0xfe;   // add 最低位1表示传回,这里把他最低位变为0,因为第一步总是先发送器件地址(方向位为0)
        
        IIC_INIT();
        start();                // 起始信号
        iicwr_byte(tt);         // 器件地址
        ack();
        iicwr_byte(command1);   // 命令1,对于24C02表示内部地址;对于PCF8591表示控制命令
        ack();
        start();                // 再来起始信号,表示我要改变方向拉
        iicwr_byte(add);        // 在传器件地址,add 最低位为1表示,下次回传数据
        ack();
        temp = iicre_byte();
        noack();
        stop();
        
        return temp;    
    }
    
    void write_byte(uchar add,uchar command1,uchar command2)
    {
        IIC_INIT();
        start();
        iicwr_byte(add);       // 器件地址
        ack();
        iicwr_byte(command1);  // 命令1,对于AT24C02表示内部地址;对于PCF8591表示控制命令
        ack();
        iicwr_byte(command2);  // command2为数据拉
        ack();
        stop();    
    }

     关于delay.c就是两个延时函数,也写成一个文件,方便调用:

     delay.h

    #ifndef __DELAY_H__
    #define __DELAY_H__
    
    #define uchar unsigned char
    #define uint  unsigned int
    
    void delay_us(uchar us);  // us级别
    void delay(uint ms);      // ms级别
    
    #endif

    delay.c

    //#include <reg52.h>
    #include "delay.h"
    
    
    void delay_us(uchar us)   
    {
        while(--us);
    }
    
    void delay(uint ms)  
    {
        uint x,y;
        for (x = ms * 32;x > 0;x--)
            for(y = 2;y > 0;y--);
    }
  • 相关阅读:
    路由重分发 最重要 最难 ccnp
    (01)Zookeeper简介
    (01)kafka以及消息系统的基本介绍
    (05)使用kafka脚本发送消息和接收消息
    (04)kafka多机多Broker(集群)的基本配置
    (03)kafka单机多Broker(伪分布式)的基本配置
    (02)安装配置kafka单Broker及其基本操作
    (02)安装zookeeper集群
    (09)使用xshell工具查看redis客户端,汉字显示乱码解决方法
    (08)redis之使用java客户端、spring连接redis、redis集群示例
  • 原文地址:https://www.cnblogs.com/hicjiajia/p/2440969.html
Copyright © 2020-2023  润新知