Files
New_STC32G_All_Board/Source/iic.c
2025-08-31 21:37:24 +08:00

350 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
}