蓝桥杯单片机----学习六之IIC协议PCF8591、AT24C04(STC15F2K60S2)

一、原理图                           

                                                                                                                                                                                                                                                                                                                                                                                   

二、软件模拟IIC

        IIC协议是一种同步、串行、半双工的通信协议,使用两根线:SDA(数据线)和SCL(时钟线)。主设备控制时钟线,负责发起和终止传输。从设备通过地址识别。

        初始化GPIO的话,需要将SDA和SCL设置为输出模式,并且初始状态是高电平,因为IIC总线在空闲时这两根线都是高电平。可能需要配置上拉电阻,确保总线空闲时能拉高。也需要配置GPIO的模式为开漏输出,这样才方便实现线与逻辑。这点可能需要特别注意,否则可能无法正确读取数据。

1、开始和终止信号

        IIC的起始信号是在SCL高电平期间,SDA从高变低。所以模拟的时候,首先确保SCL为高,然后拉低SDA,接着再拉低SCL,准备后续的数据传输。需要严格按照时序来,可能需要插入一些延时,保证信号稳定。

void I2CStart(void)
{
    sda = 1;
    scl = 1;	//拉高释放总线
	I2C_Delay(DELAY_TIME);	//延时
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

        停止信号是在SCL高电平期间,SDA从低变高。所以主设备需要先拉低SCL,然后拉低SDA,再拉高SCL,最后在SCL高的时候拉高SDA。

void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

2、数据发送

        IIC的数据是在SCL高电平时稳定的,数据的变化只能在SCL低电平时进行。每个字节传输8位,高位在前。主设备在SCL低电平时改变SDA,然后拉高SCL,从设备在SCL高电平时读取SDA。之后需要等待一个时钟周期,可能还需要检测从设备的应答信号。应答信号是在每个字节后,发送方释放SDA(变为输入模式),接收方在第九个时钟周期拉低SDA表示应答。这里模拟的时候,主设备发送完8位后,需要切换SDA为输入,等待从设备的应答,检测SDA是否为低,然后再切回输出模式继续发送。        

void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){		//由高位到地位依次发送
        scl = 0;		//拉低传输数据
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;		//拉高稳定
        byt <<= 1;		//下一位数据
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

3、应答信号

应答:数据发送信号(低电平),表示成功接收到数据,且可以继续接收。
非应答:数据接收方发送信号(高电平),表示由于某些原因不再接收数据

unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);	
    ackbit = sda; //若为1时表示接收完成
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}
void I2CSendAck(unsigned char ackbit)	//主动发送应答
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}

4、接收数据信号

        数据的读取是在SCL高电平期间(稳定),此时数据不在变化。读取完成后需主动发送应答信号来结束读取。

unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   //8位数据由高位开始
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

三、PCF8591(A/D、D/A)

 1、器件地址:

        高4位固定,后面3位对应器件引脚连接地址,蓝桥杯板子均接地(置0),最后一位控制读写操作(1为读,0为写)。

2、控制字节

第7位:固定值0;

第6位:0—A/D转换,1—D/A转换;

第5、4位:00—四路单端输入,01—三路差分输入,10—两路单端,一路差分,11—两路差分输入;

第3位:固定值0;

第2位:0—禁止自动增量,1—允许自动增量;

第1、0位:00—选择AIN0,01—选择AIN1,10—选择AIN2,11—选择AIN3.

 3、数据收发

unsigned char PCF8591_ADC(unsigned char channel)
{
	unsigned char dat;
	I2CStart();
	I2CSendByte(0x90);	//发送写地址
	I2CWaitAck();
	if(channel == 1)		//选择通道
		I2CSendByte(0x01);
	else if(channel == 3)
		I2CSendByte(0x03);
	I2CWaitAck();
	I2CStart();
	I2CSendByte(0x91);	//发送读
	I2CWaitAck();
	dat = I2CReceiveByte();		//接收数据
	I2CWaitAck();
	I2CSendAck(1);	//发送非应答信号
	I2CStop();
	return dat;
}
void PCF8591_DAC(unsigned char dat)
{
	I2CStart();
	I2CSendByte(0x90);	//发送写
	I2CWaitAck();
	I2CSendByte(0x40);	//打开DAC通道
	I2CWaitAck();	
	I2CSendByte(dat);	//发送数据
	I2CWaitAck();
	I2CSendAck(1);		//此处可删除
	I2CStop();
}

 四、AT24C04

1、器件地址

        注意:蓝桥杯板子位24C02。

2、向EEPROM写入数据

        该芯片使用9位地址进行数据寻址。

void AT24C04_write_page(unsigned char add,unsigned char *dat)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(add);
	I2CWaitAck();	
	I2CSendByte(dat[0]);
	I2CWaitAck();
	//I2CSendAck(1);
	I2CStop();
}

3、从指定地址读取数据

void AT24C04_read_page(unsigned char add,unsigned char *dat)
{
	
	I2CStart();
	I2CSendByte(0xa0);	//写操作
	I2CWaitAck();
	I2CSendByte(add);	//指定地址
	I2CWaitAck();	
	I2CStart();
	I2CSendByte(0xa1);	//读
	I2CWaitAck();
	dat[0] = I2CReceiveByte();	
	I2CSendAck(1);
	I2CStop();	
}

 tips:在数据读取时注意定时器中断,可能干扰IIC时序,最好在读取时关闭中断,结束后打开中断。

### 关于蓝桥杯单片机IIC协议的相关资料 #### IIC协议简介 IIC(Inter-Integrated Circuit)是一种简单的双向二线制同步串行总线,它只需要两根线即可实现全双工通信。这两条信号线分别是SDA(数据线)和SCL(时钟线),用于连接多个设备并进行数据传输。 #### 单片机中的IIC操作函数定义 对于单片机而言,在处理IIC协议时通常会封装一系列基本的操作函数来简化编程工作。这些基础函数包括启动条件、发送字节、等待应答以及停止条件等[^1]: ```c void IIC_Start(void); u8 IIC_SendByte(u8 dat); void IIC_WaitAck(void); void IIC_SendAck(bit ackbit); void IIC_Stop (void); ``` 上述代码片段展示了几个典型的IIC接口函数声明,它们分别负责执行IIC通讯过程中的不同阶段的任务。 #### ADC读取实例 下面是一个具体的ADC读取例子,该函数通过IIC协议从指定地址获取模拟转换后的数值,并返回给调用者作为中间变量`mid`的结果值: ```c u8 adc(u8 address) { u8 mid; IIC_Start(); IIC_SendByte(0x90); // 发送控制命令至目标器件 IIC_WaitAck(); // 等待对方回应ACK确认已接收到指令 IIC_SendByte(address); // 设置要访问的具体寄存器位置 IIC_WaitAck(); // 继续等待ACK IIC_Start(); // 再次发起START以准备接收模式切换 IIC_SendByte(0x91); // 切换到读状态 IIC_WaitAck(); // 接收端需响应ACK mid = IIC_RecByte(); // 实际读回的数据 IIC_SendAck(1); // 向发送方反馈NACK表示不再继续读更多数据 IIC_Stop(); // 结束本次交互 return mid; } ``` 这段程序实现了对特定硬件组件上的模数转换器进行配置查询的功能,具体来说就是向某款支持IIC接口的传感器发出请求并获得其当前测量得到的一个采样点位移量。 #### EEPROM写入示例 另一个重要的应用场景是对EEPROM这类非易失性存储芯片的操作。这里给出了一段针对AT24C02型号EEPROM的写入方法说明及其对应的源码实现[^2]: ```c #define PAGE_SIZE 8 /* 定义一页大小 */ #define DEVICE_ADDR 0xA0 /* 设备地址 */ void eeprom_write(u8 *write_buf, u8 addr, u8 num) { IIC_Start(); IIC_SendByte(DEVICE_ADDR | ((addr >> 7) & 0x06)); // 计算实际物理地址 IIC_WaitAck(); IIC_SendByte(addr & 0xFF); // 指定起始偏移地址 IIC_WaitAck(); while (num--) { IIC_SendByte(*write_buf++); IIC_WaitAck(); delay_us(200); // 延迟一段时间确保写入完成 } IIC_Stop(); } ``` 此部分描述了如何利用IIC协议将一组连续的数据块安全可靠地保存进外部扩展型EEPROM内存空间里去的过程;其中特别注意到了页面边界问题——即当遇到跨越两个独立页的情况时应当采取适当措施防止越界错误的发生。 #### 参数保存案例分析 在某些竞赛题目中可能会涉及到需要把一些运行期间产生的临时重要参数持久化下来以便后续恢复使用的场景。比如有这样一个需求:每当用户调整好所需设置之后按下确定键,则系统应该立即将此时最新的电压设定值乘以十再转成整数形式存放到内部编号为零号单元格的位置上[^3]: ```c // 假设已经存在一个全局变量vp代表实时监测所得电平高度 eeprom_write((u8*)&(vp * 10), 0x00, sizeof(vp)); ``` 以上语句完成了将经过放大的电压参数按照规定格式记录下来的动作,这有助于提高系统的稳定性和用户体验感。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值