1、IIC协议

SCL为高电平时,SDA线上的数据必须保持稳定,数据仅可以在SCL为低电平时改变。
(1)起始条件:当SCL为高电平的时候,SDA线上由高到低的跳变

void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

(2)结束条件:当SCL为高电平的时候,SDA线上由低到高的跳变

void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

(3)等待应答:主机向从机发送完一个字节的数据后,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据;

bit IIC_WaitAck(void)
{
    bit ackbit;
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

(4)发送应答:当主机收到来自从机发送的数据,主机也要给从机一个应答信号。低电平0表示应答,1表示非应答。

void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

其中,在iic.c文件中将如何通过I2C总线发送、接收数据的子函数也给出了:
(5)通过I2C总线发送数据

void IIC_SendByte(unsigned char byt)
{
    unsigned char i;
    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

(6)从I2C总线上接收数据

unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
			IIC_Delay(DELAY_TIME);
			da <<= 1;
			if(SDA) da |= 1;
				SCL = 0;
			IIC_Delay(DELAY_TIME);
    }
    return da;    
}

在ADC、DAC以及24C02的读写中,都需要用到IIC协议。

2、ADC

读取RB2的电压值,由于iic对时序比较严格,需要关中断

unsigned char IIC_Read(void)
{
	unsigned char iic_r;
	EA=0;
	IIC_Start();
	IIC_SendByte(0x90);//0x90为adc的写地址
	IIC_WaitAck();
	IIC_SendByte(0x03);//0x01为滑动变阻器RB2的通道
	IIC_WaitAck();
	IIC_Start();	
	IIC_SendByte(0x91);//0x91为adc的读地址
	IIC_WaitAck();	
	iic_r = IIC_RecByte();
	IIC_SendAck(1);
	IIC_Stop();
	EA = 1;
	return iic_r;
}

main.c函数:

#include "STC15F2K60S2.h"
#include "intrins.h"
#include "iic.h"
#define uchar unsigned char
#define uint unsigned int
uchar segCode[25]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,       //0~9的段码(不带小数点)
								 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf}; //0.~9.的段码(带小数点) 以及0xff全灭
uchar segVal[]={20,20,20,20,20,20,20,20};  //数码管初始化显示1 2 3 4 1. 2. 3. 4.
void SelectHC573(uchar val) 
{
	switch(val)
	{
		case 4 : P2 = (P2 & 0x1f) | 0x80; break;
		case 5 : P2 = (P2 & 0x1f) | 0xa0; break;
		case 6 : P2 = (P2 & 0x1f) | 0xc0; break;
		case 7 : P2 = (P2 & 0x1f) | 0xe0; break;
		default: P2 = (P2 & 0x1f); break;		
	}
}
void InitSystem()//系统初始化关闭蜂鸣器、继电器、LED
{
	SelectHC573(5);
	P0 = 0xbf;      //由于不同板子的引脚接法不同,此时的初始值也不同
	SelectHC573(4);	
	P0 = 0xff;     //LED全灭
}
void Timer0Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1;
}
uchar segFlag = 0;//数码管显示位标志位
uint count300ms = 0;//1s定时标志位
bit adcFlag = 1;//DS1302读时间的标志位,为1时读,为0时不
void ServiceTimer0() interrupt 1
{
	uchar pushp0,pushp2;
	pushp0 = P0;
	pushp2 = P2;//入栈
//数码管
	SelectHC573(6);
	P0 = (0x01<<segFlag);
	SelectHC573(7);	
	P0 = segCode[segVal[segFlag]];
	segFlag++;
	if(segFlag == 8) segFlag = 0;
//1s定时,DS18B20读温度
	count300ms++;
	if(count300ms>500)//300ms更新一次数值
	{
		count300ms = 0;
		adcFlag = 1;
	}
	P2 = pushp2;//出栈
	P0 = pushp0;
}
uchar adcVal;
void main()
{
	InitSystem();
	Timer0Init();
	while(1)
	{	
		if(adcFlag==1)
		{
			adcVal = IIC_Read();
			adcFlag=0;
		}
		segVal[0] = adcVal / 100;
		segVal[1] = adcVal % 100 / 10;
		segVal[2] = adcVal % 10;
	}
}

 在读取电压值时,注意不要一直读取,代码中300ms读取一次,否则在数码管显示过程中会造成闪动。

3、DAC

iic_w为0~255,代表给DAC输入的电压值:

void IIC_Write(unsigned char iic_w)
{
	EA=0;
	IIC_Start();
	IIC_SendByte(0x90);//0x90为adc的写地址
	IIC_WaitAck();
	IIC_SendByte(0x43);
	IIC_WaitAck();	
	IIC_SendByte(iic_w);
	IIC_WaitAck();
	IIC_Stop();	
	EA = 1;
}

main.c中直接调用DAC_Write()函数即可,例如想要DAC输出2V:

DAC_Write(107);

此时输入值应该为102(255/5*2),但根据实测107更接近2v

4、向24C02中写入数据

注意:24C02不能连续写,若需要写入多个数据时,应该在每写完一次后,加一个5ms左右的延时。

void IIC_Write(unsigned char add_w, unsigned char dat)
{
	EA=0;
	IIC_Start();
	IIC_SendByte(0xa0);//0xa0为24C02的写地址
	IIC_WaitAck();
	IIC_SendByte(add_w);//向24C02中为24c02_add的地址写入数据
	IIC_WaitAck();	
	IIC_SendByte(dat);//24c02_dat为写入的数据
	IIC_WaitAck();
	IIC_Stop();	
	EA = 1;
}

将0x55写入24C02中为0x01的地址:

	IIC_Write(0x01, 0x55);

5、从24C02中读数据

unsigned char IIC_Read(unsigned char add_r)
{
	unsigned char iic_r;
	EA=0;
	IIC_Start();
	IIC_SendByte(0xa0);//0xa0为24C02的写地址
	IIC_WaitAck();
	IIC_SendByte(add_r);//读取24C02中地址为add_r中的数据
	IIC_WaitAck();
	IIC_Start();	
	IIC_SendByte(0xa1);//0xa1为adc的读地址
	IIC_WaitAck();	
	iic_r = IIC_RecByte();
	IIC_SendAck(1);
	EA = 1;
	return iic_r;
}

读取24C02中地址为0x01中的数据:

c02Val = IIC_Read(0x01);