#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); } } //------------------------------------------------------------------------------------------------------------------- // @brief 内部使用用户无需关心 // @param NULL // @return void // Sample usage: 无需用户调用,用户请使用h文件中的宏定义 //------------------------------------------------------------------------------------------------------------------- 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; } //------------------------------------------------------------------------------------------------------------------- // @brief 内部使用用户无需关心 // @param NULL // @return void // Sample usage: 无需用户调用,用户请使用h文件中的宏定义 //------------------------------------------------------------------------------------------------------------------- uint8 start(void) { uint8 ret; I2CMSCR = 0x01; //发送start命令 ret = wait(); return ret; } //------------------------------------------------------------------------------------------------------------------- // @brief 内部使用用户无需关心 // @param NULL // @return void // Sample usage: 无需用户调用,用户请使用h文件中的宏定义 //------------------------------------------------------------------------------------------------------------------- uint8 send_data(char dat) { uint8 ret; I2CTXD = dat; //写数据到数据缓冲区 I2CMSCR = 0x02; //发送SEND命令 ret = wait(); return ret; } //------------------------------------------------------------------------------------------------------------------- // @brief 内部使用用户无需关心 // @param NULL // @return void // Sample usage: 无需用户调用,用户请使用h文件中的宏定义 //------------------------------------------------------------------------------------------------------------------- uint8 recv_ack(void) { uint8 ret; I2CMSCR = 0x03; //发送读ACK命令 ret = wait(); return ret; } //------------------------------------------------------------------------------------------------------------------- // @brief 内部使用用户无需关心 // @param NULL // @return void // Sample usage: 无需用户调用,用户请使用h文件中的宏定义 //------------------------------------------------------------------------------------------------------------------- char recv_data(void) //接收数据 { I2CMSCR = 0x04; //发送RECV命令 wait(); return I2CRXD; } //------------------------------------------------------------------------------------------------------------------- // @brief 内部使用用户无需关心 // @param NULL // @return void // Sample usage: 无需用户调用,用户请使用h文件中的宏定义 //------------------------------------------------------------------------------------------------------------------- uint8 send_ack(void) { uint8 ret; I2CMSST = 0x00; //设置ACK信号 I2CMSCR = 0x05; //发送ACK命令 ret = wait(); return ret; } //------------------------------------------------------------------------------------------------------------------- // @brief 内部使用用户无需关心 // @param NULL // @return void // Sample usage: 无需用户调用,用户请使用h文件中的宏定义 //------------------------------------------------------------------------------------------------------------------- void send_nak(void) { I2CMSST = 0x01; //设置NAK信号 I2CMSCR = 0x05; //发送ACK命令 wait(); } //------------------------------------------------------------------------------------------------------------------- // @brief 内部使用用户无需关心 // @param NULL // @return void // Sample usage: 无需用户调用,用户请使用h文件中的宏定义 //------------------------------------------------------------------------------------------------------------------- uint8 stop(void) { uint8 ret; I2CMSCR = 0x06; //发送stop命令 ret = wait(); return ret; } //#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设备指定地址寄存器的数据 // @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(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(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(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); }