硬件I2C(查询方式)
以STC8F2K08S2单片机为例
一、I2C相关的寄存器
① I2C 配置寄存器
② I2C 主机控制寄存器
③ I2C 主机辅助控制寄存器
④ I2C 主机状态寄存器
⑤ I2C 数据寄存器
⑥ 外设端口切换控制寄存器 1
⑦ 外设端口切换控制寄存器 2
二、程序编写
① 寄存器和相关宏定义
sfr P_SW2 = 0xBA; //外设端口切换寄存器 2
#define I2CCFG (*(unsigned char volatile xdata *)0xfe80)
#define I2CMSCR (*(unsigned char volatile xdata *)0xfe81)
#define I2CMSST (*(unsigned char volatile xdata *)0xfe82)
#define I2CTXD (*(unsigned char volatile xdata *)0xfe86)
#define I2CRXD (*(unsigned char volatile xdata *)0xfe87)
#define I2C_S0 0x10
#define I2C_S1 0x20
#define EAXFR 0x80 //I2C功能寄存器为扩展 SFR,逻辑地址位于 XDATA 区域,访问前需要将 P_SW2(BAH)寄存器的最高位(EAXFR)置 1
sbit SDA = P3^3;
sbit SCL = P3^2;
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
② 硬件I2C初始化
void init_i2c(void)
{
uchar temp = 0x00;
// //切换到第一组I2C
// temp &= ~(I2C_S0 | I2C_S1); //I2C_S0=0 I2C_S1=0
// //(P1.5/SCL, P1.4/SDA)
// //切换到第二组I2C
// temp &= ~(I2C_S0 | I2C_S1); //I2C_S0=1 I2C_S1=0
// temp |= I2C_S0; //(P2.5/SCL, P2.4/SDA)
// //切换到第三组I2C
// temp &= ~(I2C_S0 | I2C_S1); //I2C_S0=0 I2C_S1=1
// temp |= I2C_S1; //(P7.7/SCL, P7.6/SDA)
//切换到第四组I2C
temp |= (I2C_S0 | I2C_S1); //I2C_S0=1 I2C_S1=1
//(P3.2/SCL, P3.3/SDA)
temp |= EAXFR; //I2C功能寄存器为扩展 SFR,逻辑地址位于 XDATA 区域,访问前需要将 P_SW2(BAH)寄存器的最高位(EAXFR)置 1
P_SW2 = temp;
I2CCFG = 0xE0; //使能I2C主机模式
I2CMSST = 0x00;
}
③ 硬件I2C操作代码
void wait()
{
while(!(I2CMSST & 0x40));
I2CMSST &= ~0x40;
}
void start()
{
I2CMSCR = 0x01; //发送START命令
wait();
}
void send_data(uchar dat)
{
I2CTXD = dat; //写数据到数据缓冲区
I2CMSCR = 0x02; //发送SEND命令
wait();
}
void recv_ack()
{
I2CMSCR = 0x03; //发送读ACK命令
wait();
}
uchar recv_data()
{
I2CMSCR = 0x04; //发送RECV命令
wait();
return I2CRXD;
}
void send_ack()
{
I2CMSST = 0x00; //设置ACK信号
I2CMSCR = 0x05; //发送ACK命令
wait();
}
void send_nack()
{
I2CMSST = 0x01; //设置NAK信号
I2CMSCR = 0x05; //发送ACK命令
wait();
}
void stop()
{
I2CMSCR = 0x06; //发送STOP命令
wait();
}
④ BMP085 读写例程
#define BMP085_SlaveAddress 0xEE //定义器件在IIC总线中的从地址
#define OSS 0
#define p0 101325.0
uchar send[6];
xdata short ac1;
xdata short ac2;
xdata short ac3;
xdata unsigned short ac4;
xdata unsigned short ac5;
xdata unsigned short ac6;
xdata short b1;
xdata short b2;
xdata short mb;
xdata short mc;
xdata short md;
//10进制数字转ASCII字符
void Conversion(long temp_data, uchar *pAscii)
{
*(pAscii + 5) = temp_data / 100000 + 0x30; //十万
temp_data = temp_data % 100000; //取余运算
*(pAscii + 4) = temp_data / 10000 + 0x30; //万
temp_data = temp_data % 10000; //取余运算
*(pAscii + 3) = temp_data / 1000 + 0x30; //千
temp_data = temp_data % 1000; //取余运算
*(pAscii + 2) = temp_data / 100 + 0x30; //百
temp_data = temp_data % 100; //取余运算
*(pAscii + 1) = temp_data / 10 + 0x30; //十
temp_data = temp_data % 10; //取余运算
*(pAscii + 0) = temp_data + 0x30; //个
}
//单字节写入
void Single_Write(uchar SlaveAddress, uchar REG_Address, uchar REG_data)
{
start(); //起始信号
send_data(SlaveAddress); //发送设备地址+写信号
recv_ack();
send_data(REG_Address); //写寄存器地址
recv_ack();
send_data(REG_data); //写寄存器数据
recv_ack();
stop(); //发送停止信号
}
//单字节读取
uchar Single_Read(uchar SlaveAddress, uchar REG_Address)
{
uchar REG_data;
start(); //起始信号
send_data(SlaveAddress); //发送设备地址+写信号
recv_ack();
send_data(REG_Address); //写寄存器地址
recv_ack();
start(); //起始信号
send_data(SlaveAddress + 1); //发送设备地址+读信号
recv_ack();
REG_data = recv_data(); //读出寄存器数据
send_nack();
stop(); //停止信号
return REG_data;
}
//读出BMP085内部数据,连续两个
short Multiple_read(uchar SlaveAddress, uchar ST_Address)
{
uchar msb, lsb;
short _data;
start(); //起始信号
send_data(SlaveAddress); //发送设备地址+写信号
recv_ack();
send_data(ST_Address); //写寄存器地址
recv_ack();
start(); //起始信号
send_data(SlaveAddress + 1); //发送设备地址+读信号
recv_ack();
msb = recv_data(); //BUF[0]存储
send_ack(); //回应ACK
lsb = recv_data();
send_nack(); //最后一个数据需要回NACK
stop(); //停止信号
Delay5ms();
_data = msb << 8;
_data |= lsb;
return _data;
}
//BMP085读温度
long BMP085_Read_Temp(void)
{
Single_Write(BMP085_SlaveAddress, 0xF4, 0x2E);
Delay5ms(); //最大时间4.5ms
return (long)Multiple_read(BMP085_SlaveAddress, 0xF6);
}
//BMP085读压力
long BMP085_Read_Pressure(void)
{
long pressure = 0;
Single_Write(BMP085_SlaveAddress, 0xF4, 0x34);
Delay5ms(); //最大时间4.5ms
pressure = Multiple_read(BMP085_SlaveAddress, 0xF6);
pressure &= 0x0000FFFF;
return pressure;
}
//初始化BMP085,根据需要请参考pdf进行修改
void Init_BMP085()
{
ac1 = Multiple_read(BMP085_SlaveAddress, 0xAA);
ac2 = Multiple_read(BMP085_SlaveAddress, 0xAC);
ac3 = Multiple_read(BMP085_SlaveAddress, 0xAE);
ac4 = Multiple_read(BMP085_SlaveAddress, 0xB0);
ac5 = Multiple_read(BMP085_SlaveAddress, 0xB2);
ac6 = Multiple_read(BMP085_SlaveAddress, 0xB4);
b1 = Multiple_read(BMP085_SlaveAddress, 0xB6);
b2 = Multiple_read(BMP085_SlaveAddress, 0xB8);
mb = Multiple_read(BMP085_SlaveAddress, 0xBA);
mc = Multiple_read(BMP085_SlaveAddress, 0xBC);
md = Multiple_read(BMP085_SlaveAddress, 0xBE);
}
//开启转换
void BMP085_Convert()
{
long ut;
long up;
long x1, x2, b5, b6, x3, b3, p;
unsigned long b4, b7;
long temperature;
long pressure;
double altitude;
ut = BMP085_Read_Temp();
//ut = BMP085_Read_Temp(); // 读取温度
up = BMP085_Read_Pressure();
//up = BMP085_Read_Pressure(); // 读取压强
x1 = ((long)ut - ac6) * ac5 >> 15;
x2 = ((long) mc << 11) / (x1 + md);
b5 = x1 + x2;
temperature = (b5 + 8) >> 4;
Conversion(temperature, send);
uart_sendstring("Temperature: "); //温度显示
uart_sendchar(send[2]);
uart_sendchar(send[1]);
uart_sendchar('.');
uart_sendchar(send[0]);
uart_sendstring("℃\r\n");//温度单位
memset(send, 0x00, 6);
b6 = b5 - 4000;
x1 = (b2 * (b6 * b6 >> 12)) >> 11;
x2 = ac2 * b6 >> 11;
x3 = x1 + x2;
b3 = (((long)ac1 * 4 + x3) + 2)/4;
x1 = ac3 * b6 >> 13;
x2 = (b1 * (b6 * b6 >> 12)) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
b4 = (ac4 * (unsigned long) (x3 + 32768)) >> 15;
b7 = ((unsigned long) up - b3) * (50000 >> OSS);
if( b7 < 0x80000000)
p = (b7 * 2) / b4 ;
else
p = (b7 / b4) * 2;
x1 = (p >> 8) * (p >> 8);
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
pressure = p + ((x1 + x2 + 3791) >> 4);
Conversion(pressure, send);
uart_sendstring("Pressure: "); //显示压强
uart_sendchar(send[5]);
uart_sendchar(send[4]);
uart_sendchar(send[3]);
uart_sendchar('.');
uart_sendchar(send[2]);
uart_sendchar(send[1]);
uart_sendchar(send[0]);
uart_sendstring("kPa\r\n");//压强单位
memset(send, 0x00, 6);
altitude = 44330.0 * (1 - pow((float)pressure / p0, 1.0 / 5.255)) * 100;//精度cm
Conversion(altitude, send);
uart_sendstring("Altitude:"); //显示海拔
uart_sendchar(send[4]);
uart_sendchar(send[3]);
uart_sendchar(send[2]);
uart_sendchar('.');
uart_sendchar(send[1]);
uart_sendchar(send[0]);
uart_sendstring("m\r\n");//海拔单位
memset(send, 0x00, 6);
}
//主函数
void main(void)
{
init_uart();
init_i2c();
ES = 1; //使能串口中断
EA = 1; //使能总中断
Init_BMP085();
while(1){
BMP085_Convert();
uart_sendstring("\r\n");
uart_sendstring("\r\n");
uart_sendstring("\r\n");
Delay500ms();
Delay500ms();
Delay500ms();
Delay500ms();
}
}
⑤ 串口代码
#ifndef FOSC
#define FOSC 24000000L //系统频率24MHz
#endif
#define BAUD 115200 //UART波特率
sfr P_SW1 = 0xa2;
sfr AUXR = 0x8e;
sfr T2H = 0xd6;
sfr T2L = 0xd7;
bit busy;
//初始化串口
void init_uart()
{
P_SW1 = 0x00; //RXD/P3.0, TXD/P3.1
// P_SW1 = 0x40; //RXD_2/P3.6, TXD_2/P3.7
// P_SW1 = 0x80; //RXD_3/P1.6, TXD_3/P1.7
// P_SW1 = 0xc0; //RXD_4/P4.3, TXD_4/P4.4
SCON = 0x50;
T2L = (65536 - FOSC / BAUD / 4) % 256; //65536 - FOSC / BAUD / 4
T2H = (65536 - FOSC / BAUD / 4) / 256;
AUXR = 0x15; //启动定时器
}
//串口发送单个字符
void uart_sendchar(uchar dat)
{
while (busy);
busy = 1;
SBUF = dat;
}
//串口发送字符串
void uart_sendstring(uchar *p)
{
while(*p){
uart_sendchar(*p++);
}
}
//串口接收中断
void uart_isr() interrupt 4 using 1
{
if(TI){
TI = 0;
busy = 0;
}
if(RI){
RI = 0;
}
}