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--);
}
原文地址:https://www.cnblogs.com/hicjiajia/p/2440969.html