HC32003单片机芯片硬件IIC

HC32003单片机芯片硬件IIC,第1张

HC32003因为主频低,所以如果使用软件来实现IIC,通讯速率会很慢,同时而且功耗会更高,所以建议有条件的使用硬件IIC来进行通讯,硬件IIC最高速率可以到1M

1.IIC初始化


#define IIC_SCL_PIN         GpioPin2
#define IIC_SDA_PIN         GpioPin1
#define IIC_PORT            GpioPort0
void hw_iic_Init(void)
{
	stc_gpio_cfg_t stcGpioCfg;

	DDL_ZERO_STRUCT(stcGpioCfg);

	Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);	//开启GPIO时钟门控 

	stcGpioCfg.enDir = GpioDirOut;							///< 端口方向配置->输出    
	stcGpioCfg.enOD = GpioOdEnable;							///< 开漏输出
	stcGpioCfg.enPu = GpioPuEnable;							///< 端口上拉配置->使能
	stcGpioCfg.enPd = GpioPdDisable; 						///< 端口下拉配置->禁止

	Gpio_Init(IIC_PORT,IIC_SCL_PIN,&stcGpioCfg);				///< 端口初始化
	Gpio_Init(IIC_PORT,IIC_SDA_PIN,&stcGpioCfg);

	Gpio_SetAfMode(IIC_PORT,IIC_SCL_PIN,GpioAf2);				///< 配置SCL
	Gpio_SetAfMode(IIC_PORT,IIC_SDA_PIN,GpioAf2);				///< 配置SDA


	stc_i2c_cfg_t stcI2cCfg;

	DDL_ZERO_STRUCT(stcI2cCfg);								///< 初始化结构体变量的值为0
	Sysctrl_SetPeripheralGate(SysctrlPeripheralI2c,TRUE); 	///< 开启I2C0时钟门控
	stcI2cCfg.u32Pclk = Sysctrl_GetPClkFreq(); 				///< 获取PCLK时钟
	stcI2cCfg.u32Baud = 300000;								///< IIC频率,这里是300K
	stcI2cCfg.enMode = I2cMasterMode;						///< 主机模式
	stcI2cCfg.u8SlaveAddr = 0x55;							///< 从地址,主模式无效
	stcI2cCfg.bGc = FALSE; 									///< 广播地址应答使能关闭
	I2C_Init(M0P_I2C,&stcI2cCfg);						    ///< 模块初始化

	I2C_SetFunc(M0P_I2C,I2cModule_En);          			///< 启动模块
}

2.写数据函数

 ******************************************************************************
 ** \brief  主机发送函数
 ** 参数说明
 ** I2CX:填M0P_I2C
 ** iic_addr:从设备的IIC地址
 ** reg:从设备寄存器地址
 ** pu8Data:数据指针
 ** u32Len:要写数据的长度(单位:字节)
 **
 ** \retval 写数据是否成功
 **
 ******************************************************************************/
 #define HW_IIC_TIME_OUT		800    //超时计数
en_result_t I2C_MasterWriteData(M0P_I2C_TypeDef* I2CX,uint8_t iic_addr,uint8_t reg,uint8_t *pu8Data,uint32_t u32Len)
{
    en_result_t enRet = Error;
    uint8_t u8i=0,u8State;
	uint8_t reg_flag = 0;
	uint32_t time_out = HW_IIC_TIME_OUT;
    I2C_SetFunc(I2CX,I2cStart_En);
    while(1)
    {
        while(0 == I2C_GetIrq(I2CX))
        {
			time_out--;
			if(!time_out)return Error;
		}
		time_out = time_out;
        u8State = I2C_GetState(I2CX);
        switch(u8State)
        {
            case 0x08:                                 ///已发送起始条件
                I2C_ClearFunc(I2CX,I2cStart_En);
                I2C_WriteByte(I2CX,(iic_addr<<1));  ///从设备地址发送
                break;
            case 0x18:                                 ///已发送SLA+W,并接收到ACK
            case 0x28:                                 ///上一次发送数据后接收到ACK
            	if(0 == reg_flag)
				{
					I2C_WriteByte(I2CX,reg);
					reg_flag = 1;
            	}
				else 
				{
					I2C_WriteByte(I2CX,pu8Data[u8i++]);
				}
                break;
            case 0x20:                                 ///上一次发送SLA+W后,收到NACK
            case 0x38:                                 ///上一次在SLA+读或写时丢失仲裁
                I2C_SetFunc(I2CX,I2cStart_En);         ///当I2C总线空闲时发送起始条件
                break;
            case 0x30:                                 ///已发送I2Cx_DATA中的数据,收到NACK,将传输一个STOP条件
                I2C_SetFunc(I2CX,I2cStop_En);          ///发送停止条件
                break;
            default:
                break;
        }            
        if(u8i>u32Len)
        {
            I2C_SetFunc(I2CX,I2cStop_En);              ///此顺序不能调换,出停止条件
            I2C_ClearIrq(I2CX);
            break;
        }
        I2C_ClearIrq(I2CX);                            ///清除中断状态标志位
    }
    enRet = Ok;
    return enRet;
}

3读数据函数

/**
 ******************************************************************************
 ** \brief  主机读取数据函数
 ** 参数说明
 ** I2CX:填M0P_I2C
 ** iic_addr:从设备的IIC地址
 ** reg:从设备寄存器地址
 ** pu8Data:缓冲区
 ** u32Len:要读数据的长度(单位:字节)
 **
 ** \retval 写数据是否成功
 **
 ******************************************************************************/
en_result_t I2C_MasterReadData(M0P_I2C_TypeDef* I2CX,uint8_t iic_addr,uint8_t reg,uint8_t *pu8Data,uint32_t u32Len)
{
    en_result_t enRet = Error;
    uint8_t u8i=0,u8State;
    
    I2C_SetFunc(I2CX,I2cStart_En);
    uint32_t time_out = HW_IIC_TIME_OUT;
    while(1)
    {
        while(0 == I2C_GetIrq(I2CX))
        {
			time_out--;
			if(!time_out)return Error;
		}

		time_out = HW_IIC_TIME_OUT;
        u8State = I2C_GetState(I2CX);
        switch(u8State)
        {
            case 0x08:                                    //已发送起始条件,将发送SLA+R
                I2C_ClearFunc(I2CX,I2cStart_En);
                I2C_WriteByte(I2CX,(iic_addr<<1));//发送SLA+W
                break;
            case 0x18:                                    //已发送SLA+W,并接收到ACK
                I2C_WriteByte(I2CX,reg);                    //发送内存地址
                break;
            case 0x28:                                    //已发送数据,接收到ACK
                I2C_SetFunc(I2CX,I2cStart_En);
                break;
            case 0x10:                                    //已发送重复起始条件
                I2C_ClearFunc(I2CX,I2cStart_En);
                I2C_WriteByte(I2CX,(iic_addr<<1)|0x01);//读命令发送
                break;
            case 0x40:                                    //已发送SLA+R,并接收到ACK
                if(u32Len>1)
                {
                    I2C_SetFunc(I2CX,I2cAck_En);
                }
				else
				{
					I2C_ClearFunc(I2CX,I2cAck_En);
				}
				
                break;
            case 0x50:                                    //已接收数据字节,并已返回ACK信号
                pu8Data[u8i++] = I2C_ReadByte(I2CX);
                if(u8i==u32Len-1)
                {
                    I2C_ClearFunc(I2CX,I2cAck_En);        //读数据时,倒数第二个字节ACK关闭
                }
				else
				{
					I2C_SetFunc(I2CX,I2cAck_En);
				}
                break;
            case 0x58:                                    //已接收到最后一个数据,NACK已返回
                pu8Data[u8i++] = I2C_ReadByte(I2CX);
                I2C_SetFunc(I2CX,I2cStop_En);             //发送停止条件
                break;    
            case 0x38:                                    //在发送地址或数据时,仲裁丢失
                I2C_SetFunc(I2CX,I2cStart_En);            //当总线空闲时发起起始条件
                break;
            case 0x48:                                    //发送SLA+R后,收到一个NACK
                I2C_SetFunc(I2CX,I2cStop_En);
                I2C_SetFunc(I2CX,I2cStart_En);
                break;
            default:                                      //其他错误状态,重新发送起始条件
                I2C_SetFunc(I2CX,I2cStart_En);            //其他错误状态,重新发送起始条件
                break;
        }
        I2C_ClearIrq(I2CX);                               //清除中断状态标志位
        if(u8i==u32Len)                                   //数据全部读取完成,跳出while循环
        {
            break;
        }
    }
    enRet = Ok;
    return enRet;
}

4.例程调用

/**首先在调用前进行初始化*/
hw_iic_Init();
/**然后就可以调用读写函数进行 *** 作*/
//这里假设往IIC地址为0xA0的传感器中 寄存器地址为0x0F写入4个字节数据(地址自动递增)
//然后再读出来
uint8_t write_data[4] = {0x12,0x34,0x56,0x78};
uint8_t read_data[4] = {0};
//写入
I2C_MasterWriteData(M0P_I2C,0xA0,0x0F,write_data,4);
//读出
I2C_MasterReadData(M0P_I2C,0xA0,0x0F,read_data,4);

5.注意事项

  1. 上面的代码并不是完整的工程,这里是标示出关键的代码,真正运用到工程请根据编译器提示增加相应的头文件
  2. 调用例程中的地址和寄存器只是假设,请根据项目实际修改

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/725586.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-26
下一篇 2022-04-26

发表评论

登录后才能评论

评论列表(0条)

保存