#include "iic.h" //------------------------------------------------------------------------------------------------------------------- // @brief 内部使用用户无需关心 // @param NULL // @return void // Sample usage: 无需用户调用,用户请使用h文件中的宏定义 //------------------------------------------------------------------------------------------------------------------- void iic_delay_us(uint16 x) //33.1776Mhz { uint8 i; while(x--) { i = 9; while (--i); } } uint8 wait(void) { uint16 count = 0; uint8 ret = IIC_SEND_OK; while (!(I2CMSST & 0x40)) { iic_delay_us(1); if(count++ >= 30)//等待超过30us,则退出等待。 { ret = IIC_SEND_FAIL; break; } } I2CMSST &= ~0x40; return ret; } uint8 start(void) { uint8 ret; I2CMSCR = 0x01; //发送start命令 ret = wait(); return ret; } uint8 send_data(char dat) { uint8 ret; I2CTXD = dat; //写数据到数据缓冲区 I2CMSCR = 0x02; //发送SEND命令 ret = wait(); return ret; } uint8 recv_ack(void) { uint8 ret; I2CMSCR = 0x03; //发送读ACK命令 ret = wait(); return ret; } char recv_data(void) //接收数据 { I2CMSCR = 0x04; //发送RECV命令 wait(); return I2CRXD; } uint8 send_ack(void) { uint8 ret; I2CMSST = 0x00; //设置ACK信号 I2CMSCR = 0x05; //发送ACK命令 ret = wait(); return ret; } void send_nak(void) { I2CMSST = 0x01; //设置NAK信号 I2CMSCR = 0x05; //发送ACK命令 wait(); } uint8 stop(void) { uint8 ret; I2CMSCR = 0x06; //发送stop命令 ret = wait(); return ret; } void iic_scan(void) { uint8 i; for(i = 0; i <= 0x7F; i++) { //7位SlaveAddress uint8 ACK_or_NACK = 0; start(); printf("."); send_data((i << 1) | 0); //I2C从地址+写标志 I2CMSCR = 0x03; while(!(I2CMSST & 0x40)); if(I2CMSST & 0x02) //判断I2CMSST的bit1 MSACKI,读入的ACK信号为低即是ACK,为高为NACK. ACK_or_NACK = 0; //MSACKI=1=NACK=没有正确收到ACK信号 else ACK_or_NACK = 1; //MSACKI=0=ACK=正确收到ACK信号 I2CMSST &= ~0x40; //清除中断标志 if(ACK_or_NACK) { printf("\r\nFound Device Address:0x%02X\r\n", i); // UART_SendHex(i); // printf("%02x",i); } else { stop(); } } } //#define UNUSED(expr1, expr2) do { if(scl_pin == sda_pin); } while (0) //------------------------------------------------------------------------------------------------------------------- // @brief 硬件IIC初始化 // @param iic_n 选择IIC模块 // @param wait_time I2C总线速度(等待时钟数)控制: 速度设置为等待wait_time*2+1个时钟 // @return void // Sample usage: //------------------------------------------------------------------------------------------------------------------- void iic_init(IICN_enum iic_n, uint8 wait_time) { //UNUSED(scl_pin); //__attribute__ ((unused))(sda_pin); //UNUSED(scl_pin, sda_pin); P_SW2 &= ~(0x03<<4); P_SW2 |= 1<<7; //将EAXFR寄存器置1,这样才能使用特殊功能寄存器为扩展SFR,访问逻辑地址位于 XDATA 区域 switch(iic_n) { case IIC_1: P_SW2 |= (0x00<<4); //SCL:P1.5 SDA:P1.4 break; case IIC_2: P_SW2 |= (0x01<<4); //SCL:P2.5 SDA:P2.4 break; case IIC_3: P_SW2 |= (0x02<<4); //SCL:P7.7 SDA:P7.6 break; case IIC_4: P_SW2 |= (0x03<<4); //SCL:P3.2 SDA:P3.3 break; } I2CCFG |= 1<<6; //主机模式 I2CCFG |= 1<<7; //使能IIC I2CCFG |= wait_time&0x3F;//速度设置为等待wait_time*2+1个时钟 I2CMSST = 0x00; //主机状态寄存器 } //------------------------------------------------------------------------------------------------------------------- // @brief 写入一个字节数据到I2C设备指定寄存器地址 // @param iic_n IIC模块(IIC_1,IIC_2,IIC_3,IIC_0) // @param slaveid 从机地址(7位地址) // @param reg 从机寄存器地址 // @param dat 需要发送的数据 // @return 返回的状态值 0:成功 1:失败 // @since v2.0 // Sample usage: iic_write_reg(0x2D, 0x50,2); //写入数据2到0x50地址,从机地址为0x2D //------------------------------------------------------------------------------------------------------------------- uint8 iic_write_reg(uint8 dev_add, uint8 reg, uint8 dat) { if(start() != IIC_SEND_OK) return IIC_SEND_FAIL; if(send_data((dev_add<<1) | 0x00) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; if(send_data(reg) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; if(send_data(dat) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; if(stop() != IIC_SEND_OK) return IIC_SEND_FAIL; return IIC_SEND_OK; } //------------------------------------------------------------------------------------------------------------------- // @brief 写入多个字节数据到I2C设备指定寄存器地址 //------------------------------------------------------------------------------------------------------------------- uint8 iic_write_reg_bytes(uint8 dev_add, uint8 reg, uint8 *dat, uint8 num) { if(start() != IIC_SEND_OK) return IIC_SEND_FAIL; if(send_data((dev_add<<1) | 0x00) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; if(send_data(reg) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; while(num--) { if(send_data(*dat) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; dat++; } // if(recv_ack() != IIC_SEND_OK) // return IIC_SEND_FAIL; if(stop() != IIC_SEND_OK) return IIC_SEND_FAIL; return IIC_SEND_OK; } //------------------------------------------------------------------------------------------------------------------- // @brief 读取I2C设备指定地址寄存器的数据 // @param iic_n I2C通道号及引脚 // @param dev_add 从机地址(7位地址) // @param reg 从机寄存器地址 // @param dat 数据地址 // @return 读取的寄存器值 // @since v1.0 // Sample usage: uint8 value = iic_read_reg(i2c0, 0x2D, 0x50);//读取0x50地址的数据,从机地址为0x2D //------------------------------------------------------------------------------------------------------------------- uint8 iic_read_reg(uint8 dev_add, uint8 reg, uint8 *dat) { if(start() != IIC_SEND_OK) return IIC_SEND_FAIL; if(send_data((dev_add<<1) | 0x00) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; if(send_data(reg) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; // if(stop() != IIC_SEND_OK) // return IIC_SEND_FAIL; if(start() != IIC_SEND_OK) return IIC_SEND_FAIL; // if(start() != IIC_SEND_OK) // return IIC_SEND_FAIL; if(send_data((dev_add<<1) | 0x01) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; *dat = recv_data(); //读取数据 if(send_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; if(stop() != IIC_SEND_OK) return IIC_SEND_FAIL; return IIC_SEND_OK; } //------------------------------------------------------------------------------------------------------------------- // @brief 读取I2C设备指定地址寄存器的数据 // @param iic_n I2C通道号及引脚 // @param dev_add 从机地址(7位地址) // @param reg 从机寄存器地址 // @param dat 读取的数据存储的地址 // @param num 读取字节数 // @return void // @since v1.0 // Sample usage: uint8 value = i2c_read_reg(i2c0, 0x2D, 0x50, 10, buf);//读取0x50地址的数据,从机地址为0x2D开始的10个字节 //------------------------------------------------------------------------------------------------------------------- uint8 iic_read_reg_bytes(uint8 dev_add, uint8 reg , uint8 *dat, uint8 num) { if(start() != IIC_SEND_OK) return IIC_SEND_FAIL; if(send_data((dev_add<<1) | 0x00) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; if(send_data(reg) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; // if(stop() != IIC_SEND_OK) // return IIC_SEND_FAIL; if(start() != IIC_SEND_OK) return IIC_SEND_FAIL; if(send_data((dev_add<<1) | 0x01) != IIC_SEND_OK) return IIC_SEND_FAIL; if(recv_ack() != IIC_SEND_OK) return IIC_SEND_FAIL; while(num--) { *dat = recv_data(); //读取数据 if(num==0) { send_nak(); } else { if(send_ack() != IIC_SEND_OK) { return IIC_SEND_FAIL; } dat++; } } // *dat = recv_data(); // if(send_ack() != IIC_SEND_OK) // return IIC_SEND_FAIL; if(stop() != IIC_SEND_OK) return IIC_SEND_FAIL; return IIC_SEND_OK; } //------------------------------------------------------------------------------------------------------------------- // @brief 硬件IIC引脚切换函数 // @param iic_n I2C通道号及引脚 // @param scl_pin 选择SCL引脚 // @param sda_pin 选择SDA引脚 // Sample usage: //------------------------------------------------------------------------------------------------------------------- void iic_change_pin(IICN_enum iic_n) { P_SW2 |= 1<<7; //将EAXFR寄存器置1,这样才能使用特殊功能寄存器为扩展SFR,访问逻辑地址位于 XDATA 区域 P_SW2 &= ~(0x03<<4); //清除引脚切换位 switch(iic_n) { case IIC_1: P_SW2 |= (0x00<<4); //SCL:P1.5 SDA:P1.4 break; case IIC_2: P_SW2 |= (0x01<<4); //SCL:P2.5 SDA:P2.4 break; case IIC_3: P_SW2 |= (0x02<<4); //SCL:P7.7 SDA:P7.6 break; case IIC_4: P_SW2 |= (0x03<<4); //SCL:P3.2 SDA:P3.3 break; } P_SW2 &= ~(1<<7); }