STC8系列单片机硬件I2C使用教程(一)

    科技2022-07-11  114

    硬件I2C(查询方式)以STC8F2K08S2单片机为例

    一、I2C相关的寄存器① I2C 配置寄存器② I2C 主机控制寄存器③ I2C 主机辅助控制寄存器④ I2C 主机状态寄存器⑤ I2C 数据寄存器⑥ 外设端口切换控制寄存器 1⑦ 外设端口切换控制寄存器 2 二、程序编写① 寄存器和相关宏定义② 硬件I2C初始化③ 硬件I2C操作代码④ BMP085 读写例程⑤ 串口代码

    一、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; } }
    Processed: 0.009, SQL: 8