i2c.h
#ifndef I2C_H
#define I2C_H
#include <STC8H.H>
sbit SCL = P3^2;
sbit SDA = P3^3;
static bit I2C_Flage;
/*P_SW2*/
#define EAXFR 0x80; //XFR寄存器使能
#define I2C_S 0x30; //I2C功能引脚切换,SCL:P3.2,SDA:P3.3
/*I2C配置寄存器 I2CCFG*/
#define ENI2C 0x80 //I2C功能控制位;1:允许I2C功能,0:禁止I2C功能
#define MSSL 0x40 //I2C工作模式选择位;1:主机模式,0:从机模式
#define MSSPEED 0x3C //I2C总线速度(等待时钟数)控制,范围0~63(0x3F),I2C总线速度 = F_OSC/2/(x*2+4)
/*I2C主机控制寄存器 I2CMSCR*/
#define EMSI 0x80 //主机模式中断使能控制位;1:允许主机模式的中断,0:关闭主机模式的中断
//unsigned char MSCMD = 0x00; /主机命令,0x00时,待机,无动作
#define I2C_START 0x01 //起始命令
#define I2C_SEND_DATA 0x02 //发送数据命令
#define I2C_RECEVIVE_ACK 0x03 //接收 ACK 命令
#define I2C_RECEVIVE_DATA 0x04 //接收数据命令
#define I2C_SEND_ACK 0x05 //发送 ACK 命令
#define I2C_STOP 0x06 //停止信号
#define I2C_START_DATA_ACK 0x09 //起始命令,发送数据命令,接收ACK命令依次执行。
#define I2C_SEND_DATA_ACK 0x0A //发送数据命令,接收 ACK 命令依次执行。
#define I2C_RECEVIVE_DATA_ACK 0x0B //接收数据命令,发送 ACK 命令依次执行。
#define I2C_RECEVIVE_DATA_NAK 0x0C //接收数据命令,发送 NAK 命令依次执行。
/*I2C主机辅助控制寄存器 I2CMSAUX*/
#define WDTA 0x01 //主机模式I2C数据自动发送允许位,1:使能自动发送,0:禁止自动发送
/*I2C主机状态寄存器 I2CMSST*/
#define MSBUSY 0x80 //主机模式I2C控制状态位(只读位)1:忙碌状态,0:空闲状态
//(发送完START信号后,控制器会进入忙碌状态,一直持续到成功发送STOP停止信号)
#define MSIF 0x40 //主机模式中断标志位。
#define MSACKI 0x02 //主机模式接收应答位。(只读位)
#define MSACKO 0x01 //主机模式发送应答位。
void I2C_Init(void);
void I2C_Start(void); //起始信号
void I2C_Stop(void); //终止信号
void I2C_ACK_S(bit A); //发送应答信号
void I2C_ACK_R(void); //接收应答信号
void I2C_SendByte(unsigned char dt); //发送数据
unsigned char I2C_ReceiveByte(void); //接收数据
#endif
i2c.c
#include "i2c.h"
void I2C_Init(void) //I2C初始化
{
P_SW2 |= EAXFR; //XFR寄存器使能
P_SW2 |= I2C_S; //I2C引脚
I2CCFG = ENI2C|MSSL|MSSPEED; //允许I2C功能,主机模式
I2CMSST = 0x00;
}
void I2C_Start(void) //起始信号
{
I2C_Flage = 1;
I2CMSCR = EMSI|I2C_START; //起始命令
while(I2C_Flage); //等待MSCMD命令执行完毕
}
void I2C_Stop(void) //终止信号
{
I2C_Flage = 1;
I2CMSCR = EMSI|I2C_STOP; //停止命令
while(I2C_Flage); //等待MSCMD命令执行完毕
}
void I2C_ACK_R(void) //接收应答信号
{
I2C_Flage = 1;
I2CMSCR = EMSI|I2C_RECEVIVE_ACK ; //接收 ACK 命令
while(I2C_Flage); //等待MSCMD命令执行完毕
}
void I2C_ACK_S(bit A) //发送应答信号
{
/*
发送"0101"命令到I2CMSCR寄存器的MSCMD位后,
控制器会自动读取I2CMSST的MSACKO位的数据当作ACK数据发送到SDA。
*/
if(A == 1)
I2CMSST |= MSACKO; //非应答信号
else
I2CMSST &= ~MSACKO; //应答信号
I2C_Flage = 1;
I2CMSCR = EMSI|I2C_SEND_ACK ; //发送 ACK 命令
while(I2C_Flage); //等待MSCMD命令执行完毕
}
void I2C_SendByte(unsigned char dt) //发送数据
{
I2CTXD = dt; //写数据到数据缓冲区
I2C_Flage = 1;
I2CMSCR = EMSI|I2C_SEND_DATA; //发送数据命令
while(I2C_Flage); //等待MSCMD命令执行完毕
}
unsigned char I2C_ReceiveByte(void) //接收数据
{
I2C_Flage = 1;
I2CMSCR = EMSI|I2C_RECEVIVE_DATA; //接收数据命令
while(I2C_Flage); //等待MSCMD命令执行完毕
return I2CRXD;
}
void I2C_Isr(void) interrupt 24
{
/*主机模式的I2C控制器执行完I2CMSCR寄存器中MSCMD命令后,
会产生中断信号,硬件自动将MSIF位置一,向CPU发出中断请求,
响应中断后, MSIF位必须软件清零*/
if(I2CMSST & MSIF)
{
I2CMSST &= ~MSIF; //中断标志位清零
I2C_Flage = 0;
}
}
main.c
#include "i2c.h"
#include "led_segment.h"
//unsigned char temp[4] = {0};
/*控制字 CONTROL_BYTE*/
/*通道号,CHANNEL_NUMBER */
#define CH0 0x00
#define CH1 0x01
#define CH2 0x02
#define CH3 0x03
/*自动增益*/
#define AUTO_INCREMENT 0x04;
/*模拟输入控制
四单端输入:0x00
三差分输入(AIN3为负):0x10
两单端输入(AIN0,AIN1)一差分输入:0x20 ;
两差分输入(AIN1,AIN3为负):0x30*/
#define ANALOGUE_INPUT 0x00
/*模拟输出使能*/
#define ANALOGUE_OUTPUT_ENABLE 0x40
//仅模拟输出,D/A转换
void PCF8591_DAC(unsigned char addr,unsigned char value)
{
I2C_Start(); //起始信号
I2C_SendByte(addr); //发送地址,写
I2C_ACK_R(); //接收应答
I2C_SendByte(ANALOGUE_OUTPUT_ENABLE); //发送控制字
I2C_ACK_R(); //接收应答
I2C_SendByte(value); //发送数据
I2C_ACK_R(); //接收应答
I2C_Stop(); //终止信号
}
//仅单通道读取,A/D转换
unsigned char PCF8591_ADCS(unsigned char addr,unsigned char CONTROL_BYTE)
{
unsigned char temp;
I2C_Start(); //起始信号
I2C_SendByte(addr); //发送地址,写
I2C_ACK_R(); //接收应答
I2C_SendByte(CONTROL_BYTE); //发送控制字,四单端输入
I2C_ACK_R(); //接收应答
I2C_Start(); //起始信号
I2C_SendByte(addr|0x01); //发送地址,读
I2C_ACK_R(); //接收应答
I2C_ReceiveByte(); //接收空数据
I2C_ACK_S(0); //发送应答
temp = I2C_ReceiveByte(); //接收数据
I2C_ACK_S(1); //发送非应答
I2C_Stop(); //终止信号
return temp;
}
void main (void)
{
unsigned char temp;
unsigned int V;
P3M0 = 0x00;
P3M1 = 0x00;
EA = 1;
I2C_Init();
SEG_GPIO_Init();
while(1)
{
temp = PCF8591_ADCS(0x90,0x03);
PCF8591_DAC(0x90,temp);
V = temp*1.953125; // 5/256*100
LED_7SEG_CAT_Display(V,2);
}
}
/*
连续读取四个数据,A/D转换
若仅单端输入,则依次读取四个通道数据
void PCF8591_ADC(unsigned char addr,unsigned char CONTROL_BYTE,unsigned char temp[])
{
I2C_Start(); //起始信号
I2C_SendByte(addr); //发送地址,写
I2C_ACK_R(); //接收应答
I2C_SendByte(AUTO_INCREMENT|CONTROL_BYTE);//发送控制字,自动增益
I2C_ACK_R(); //接收应答
I2C_Start(); //起始信号
I2C_SendByte(addr|0x01); //发送地址,读
I2C_ACK_R(); //接收应答
I2C_ReceiveByte(); //接收空数据
I2C_ACK_S(0); //发送应答
temp[0] = I2C_ReceiveByte(); //接收数据
I2C_ACK_S(0); //发送应答
temp[1] = I2C_ReceiveByte(); //接收数据
I2C_ACK_S(0); //发送应答
temp[2] = I2C_ReceiveByte(); //接收数据
I2C_ACK_S(0); //发送应答
temp[3] = I2C_ReceiveByte(); //接收数据
I2C_ACK_S(1); //发送非应答
I2C_Stop(); //终止信号
}
*/