蓝桥杯嵌入式准备IIC(24C02 and MCP4017)

IIC基本结构:

多主机IIC总线系统:

IIC 是一种总线,就两根线,两根线上可以挂很多设备也就是所说的两线式串行总线,由PHILIPS公司开发用于微型控制器及其外围设备。

他是由数据线SDA和时钟线SCL构成的串行总线,可发送和接受数据。在CPU与被控IC之间,IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。

IIC是半双工通信方式。

IIC总线是不同的IC或者模块之间双向两线通信。这两条线是串行数据线(SDA)和串行时钟线(SCL)。这两条线必须通过上拉电路连接至正电源。数据传输只能在总线不忙时启动。

开始、停止信息:

数据和时钟线在总不忙时保持高电平。时钟为高电平数据线上的一个由高到底的变化被定义为开始条件

在比赛中IIC基本的时序是自己写的,比赛的时候会给我们一个资料盘,里边会有IIC的底层代码

void I2CStart(void)
{
    SDA_Output(1);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SDA_Output(0);
    delay1(DELAY_TIME);
    SCL_Output(0);
    delay1(DELAY_TIME);
}

/**
  * @brief I2C结束信号
  * @param None
  * @retval None
  */
void I2CStop(void)
{
    SCL_Output(0);
    delay1(DELAY_TIME);
    SDA_Output(0);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SDA_Output(1);
    delay1(DELAY_TIME);

}

 应答信号ACK:

发送器发送一个字节,就在时钟脉冲期9间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答信号(ACK简称应答位),表示接收器已经成功接受该字节,应答信号为高电平时,规定为非应答信号,(NACK),一般表示接收器接受该字节没有成功。

 

/**
  * @brief I2C等待确认信号
  * @param None
  * @retval None
  */
unsigned char I2CWaitAck(void)
{
    unsigned short cErrTime = 5;
    SDA_Input_Mode();
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    while(SDA_Input())//主机在第九个时钟脉冲的时候去读SDA的数据如果是0,则接收到应答信号
    {
        cErrTime--;
        delay1(DELAY_TIME);
        if (0 == cErrTime)
        {
            SDA_Output_Mode();
            I2CStop();
            return ERROR;
        }
    }
    SDA_Output_Mode();
    SCL_Output(0);
    delay1(DELAY_TIME);
    return SUCCESS;
}

/**
  * @brief I2C发送确认信号
  * @param None
  * @retval None
  */
void I2CSendAck(void)//主机发送ACK
{
    SDA_Output(0);
    delay1(DELAY_TIME);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SCL_Output(0);
    delay1(DELAY_TIME);

}

/**
  * @brief I2C发送非确认信号
  * @param None
  * @retval None
  */
void I2CSendNotAck(void)//发送非应答信号
{
    SDA_Output(1);
    delay1(DELAY_TIME);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SCL_Output(0);
    delay1(DELAY_TIME);

}

 

数据信息:

一个数据位在每一个时钟脉冲期间传输,SDA线上的数据必须在时钟脉冲的高电压期间保持稳定,(就是在时钟信号为高电平的时候读取数据)这个期间数据线上的变化被当做控制信号。

/**
  * @brief I2C发送一个字节
  * @param cSendByte 需要发送的字节
  * @retval None
  */
void I2CSendByte(unsigned char cSendByte)
{
    unsigned char  i = 8;
    while (i--)
    {
        SCL_Output(0);
        delay1(DELAY_TIME);
        SDA_Output(cSendByte & 0x80);
        delay1(DELAY_TIME);
        cSendByte += cSendByte;//自加的操作相当于左移一位
        delay1(DELAY_TIME);
        SCL_Output(1);
        delay1(DELAY_TIME);
    }
    SCL_Output(0);
    delay1(DELAY_TIME);
}

/**
  * @brief I2C接收一个字节
  * @param None
  * @retval 接收到的字节
  */
unsigned char I2CReceiveByte(void)
{
    unsigned char i = 8;
    unsigned char cR_Byte = 0;
    SDA_Input_Mode();
    while (i--)
    {
        cR_Byte += cR_Byte;
        SCL_Output(0);
        delay1(DELAY_TIME);
        delay1(DELAY_TIME);
        SCL_Output(1);
        delay1(DELAY_TIME);
        cR_Byte |=  SDA_Input();
    }
    SCL_Output(0);
    delay1(DELAY_TIME);
    SDA_Output_Mode();
    return cR_Byte;
}

 空闲状态:

IIC总线的SDA和SCL两条信号线同处于高电平的时候,规定总线的状态为空闲状态。此时各个器件的输出级场效应管均处于截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高 。

24C02存储器基本原理:(两线串行EEROM—24C01/02/04/08/16)

概述和特点:

 主要特性:

 

 

 在咱们嵌入式板子中的模块:

24C02的芯片地址为1010(A2 A1 A0)(R=1,W=0)最后一位读写位

所以芯片的地址可以敲定为:

10100000(0xA0)写或者

10100001(0xA1)读

 E1,E2 E3 为地址引脚都接地

 个引脚的作用:

结构框图:

 注意的是:AT24C02存储器进行页读写的时候,不能产生跨页的现象

而对我们编程来说最重要的是下边的写操作:

写操作时序:

按照字节来写:

AT24C02存储器写操作需要再给出开始态、器件地址和确认后,紧跟着给出一个8位数据地址。一经收到该地址,EEPROM就通过SDA发送确认信号(ACK),并随时钟输入八个位的数据。在收到8位数据后,EEPROM将通过SDA对主机发送信号,数据传输设备(主机)必须用停止状态来中止写操作,然后EEPROM进入一个内记时固定存储器写入周期。在写周期时,所有输入被禁止,EEPROM直到写完后在应答,如下图片

//该代码在比赛中是要自己写的
/**
  * @brief 往AT24C02里写数据
  * @param 将要写的内容放到pucBuff:数组  unAddr:入口地址 ucNum数据个数
  * @retval None
  */
void IIC_AT24C02_write(unsigned char * pucBuff,unsigned char unAddr,unsigned char ucNum)
{
	I2CStart();//开始信号
	I2CSendByte(0xa0);//写器件地址
	I2CWaitAck();//等待从机回复应答信号(ACK)
	
	I2CSendByte(unAddr);//发送数据地址
	I2CWaitAck();//等待从机回复应答信号(ACK)
	
	while(ucNum--)//几个数据
	{
		I2CSendByte(* pucBuff++);//每次发送一个字节的数据
  	I2CWaitAck();//没发送完一个数据都有一个应答信号
	}
	
	I2CStop();//发送停止
	delay1(500);//延时函数
}

 按照页面来写:

1KB/2KB EEPROM能进行8字节页面写入,4KB、8KB、16KB设备能进行16字节页面写入。激发写页面与激发写字节相同,只是数据传输设备无需再第一个字节随时钟输入后,发出一个停止状态。再EEPROM确认收到第一个数据之后,数据传输设备能在传输7个或者15个数据,每个数据收到之后,EEPROM都将通过SDA回送一个确认信号,,最后数据传输设备必须通过停止状态终止页面写序列。


/**
  * @brief 从AT24C02里读数据  内存大小(256*8bit)2k
	* @param 将读取的数据存到数组里边pucBuff:数组  unAddr:入口地址 ucNum:数据个数
  * @retval None
  */
void IIC_AT24C02_read(unsigned char * pucBuff,unsigned char unAddr,unsigned char ucNum)
{
	//先写入读的地址
	I2CStart();//开始信号
	I2CSendByte(0xa0);//写操作地址
	I2CWaitAck();//等到应答信号
	
	I2CSendByte(unAddr);//发送数据地址位
	I2CWaitAck();//等待应答
	
	//第八位写高执行读EEPROM操作
	I2CStart();//发送开始信号
	I2CSendByte(0xa1);//发送读操作地址
	I2CWaitAck();//等待应答
	
	while(ucNum--)//个数
	{
		*pucBuff++=I2CReceiveByte();//将读取的数据放到数组里
		if(ucNum)
			I2CSendAck();
		else
			I2CSendNotAck();
	}
	
	I2CStop();
}

 

 注意:数据字地址的低三位(1KB/2KB)或者低四位(4KB、8KB、16KB)在接收到每个数据字之后,内部自动加一,数据字地址的高位字节保持不变,以保持存储器页地址不变。如果传送到EEPROM中的数据字超过8位或者16位数据字节地址将会滚动以前的数据将被覆盖。

工程建立:

将官方提供的IIC例程移植到自己的工程里边,将上边所写的读写AT24C02的操作加到自己的代码当中,然后声明一下。

 

那么接下来该如何使用一下这个代码呐

首先先在main.c文件调用IIC的h文件,然后在主函数中初始化IIC的初始化函数, I2CInit;

现在前提准备就做好了,开始尝试往EEPROM里边写数据,

根据咱们所写的代码就可以知道,现在我们还缺少EEPROM相关变量来传输数据,

定义两个数组,以五个空间大小为例

 然后来看一下咱们之前写的代码IIC_AT24C02_write(....入口参数...)等怎么用

///AT24C02:写入数据
	IIC_AT24C02_write(EEROM_write,0,5);
//第一个入口参数是一个数组地址,指向将要存储的数据
//第二个参数,入口地址,从零开始
//第三个参数,需要多少个数据

	HAL_Delay(100);//实际赛题的时候写操作和读操作一般不会挨得这么近,就不用加延时函数,否则显示出错

	IIC_AT24C02_read(EEROM_read,0,5);
//第一个入口参数是一个数组地址,指向将要存储读取数据
//第二个参数,入口地址,从零开始
//第三个参数,需要读多少个数据

将上述代码加到主函数里边,咱们可以将读取的数据通过LCD显示出来如下图所示

 

 MCP4017可编程电阻原理:

什么是可编程电阻,他的阻值和我们的滑动电阻还不一样,滑动变阻是通过物理的方式进行旋转来改变阻值,但是可编程电阻是通过软件的形式对其进行电阻值的修改,对应的开发板的U3位置。

开发板接线图:

 104啥意思呢?

10*10^4=100K的电阻

怎么修改电阻值?

硬件配置:

首先先来看一下内部结构:

 他的内部分为三大块,电源、IIC数据、电阻器网络

根据原理图和内部结构的提示可以知道A没有连接(Note.2)(在某些配置中,此信号可能未连接到外部存储器(内部浮动或接地)。)

再来看一下内部电阻网是怎么变化的

雨刮器电阻(也就是我说的小开关)取决于抽头。
也就是说,每个抽头选择电阻具有小的变化。这种变化对RAB电阻较小(5.0 kΩ)的器件影响更大

内部有127个可控制小开关也就是N的个数就是Rs的个数,通过给他一个不同的N值他的电阻值会发生变化

在芯片手册里提供了一个公式:

和雨刮器电阻值的设置范围:

再来看一下4017地址:

这点和上边的24C02有区分

有芯片手册可以知道地址的前七位是被固定了的为0101111最后一位来决定是以读的形式来写还是以写的程序来写。

软件编程:

写一个字节:

 

 我们只需要把器件地址写好然后把N值写进去即可。

 

/**
  * @brief 往MCP4017里边写数据
  * @param resist_val也就是传入的N的值//根据雨刷器电阻可设置的范围可知为(0~7F)
  * @retval None
  */
//MCP4017可编程芯片
void write_MCP4017(uint8_t resist_val)
{
	I2CStart();//起始信号
	I2CSendByte(0x5E);//0101 1110  器件地址和写操作
	I2CWaitAck();//等待应答
	
	I2CSendByte(resist_val);//发送数据
	I2CWaitAck();
	I2CStop();
}

 读取电阻值:

 

/**
  * @brief 从MCP4017里读取电阻值
	* @param resist_val:
  * @retval None
  */
/*********用于接收电阻的值***********/
uint8_t resist_val;//将接受的N值给到一个变量里边
/**************END******************/
uint8_t read_MCP4017(void)
{
	uint8_t value;
	//先写入读的地址
	I2CStart();//起始信号
	I2CSendByte(0x5f);//0101 1111 读操作 
	I2CWaitAck();
	
	value=I2CReceiveByte();
	I2CSendNotAck();
	I2CStop();
	
	return value;
}//读出来的是原始数据,不是真正的电阻值

电阻的计算:

100000/127约等于787.4Ω,所以Rs=0.7874KΩ,根据公式假设要设置一个10k的电阻

10K=0.7874*N

N=12.7近似等于13=d

//N值写入
write_MCP4017(0x0d);
//lcd显示代码
	//MCP4017 : 可编程电阻测试
	resist_val=read_MCP4017();
	sprintf((char *)MCP4017_Disp,"4017:Rx=%x Rwb=%5.3f  ",resist_val,0.7874*resist_val);
	LCD_DisplayStringLine(Line2,MCP4017_Disp);
	sprintf((char *)MCP4017_Disp,"4017:U=%3.3f          ",3.3*((0.7874*resist_val)/(0.7874*resist_val+10)));
	LCD_DisplayStringLine(Line3,MCP4017_Disp);

 

4017的第二行就是电压的转换,3.3乘以(4017的电阻/总电阻值)

  • 8
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值