历史上的今天
今天是:2024年09月03日(星期二)
2019年09月03日 | STM32小白入门(第12天)---I2C协议
2019-09-03 来源:eefocus

一、概述



二、信号概念

三、AT24C02(EEPROM电可擦除ROM)--配合单片机存贮掉电前需要保存的数据,类似单片机的硬盘

1、写时序

2、读时序

思考题2:在24c02控制时钟的时候,为什么要进行5us的延时,小于5us延时或许大于5us的延时是否可以,示例代码如下:
//设置SCL高电平
SCL=1;
delay_us(5);
//设置SCL低电平
SCL=0;
delay_us(5);
回答:大于5us是可以的,如果使用5ms是可以的。但是延时是不能低于1.2us,详细描述如下图。


3、起始信号和停止信号

//sda输入输出模式切换函数
void OLED_SDA_Mode(GPIOMode_TypeDef IOMode)
{
//PB9初始化设置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = OLED_SDA_PIN; //9号引脚
GPIO_InitStructure.GPIO_Mode = IOMode; //输出模式/输入模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,驱动LED需要电流驱动
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(OLED_GPIO_PORT, &GPIO_InitStructure); //初始化GPIOB,把配置的数据写入寄存器
}
/**********************************************
//IIC Start
**********************************************/
void IIC_Start(void)
{
//保证SDA引脚为输出模式
OLED_SDA_Mode(GPIO_Mode_OUT);
OLED_SCLK = 1;
OLED_SDA_W = 1;
/*注:原版代码是没有加延时的,这里一定要延时,因为M4是高速芯片,3.3MHz通信速率,所以一个时钟周 期约为0.3us,有与我们处理器是168MHz,执行一条指令比这个时间快很多所以我们需要加至少1us的延时,
但是在频率较低的处理器中我们可以不加延时
*/
delay_us(1);
OLED_SDA_W = 0; //数据线先拉低,时钟线后拉低,即为启动信号
delay_us(1);
OLED_SCLK = 0;
delay_us(1);
}
/**********************************************
//IIC Stop
**********************************************/
void IIC_Stop(void)
{
//保证SDA引脚为输出模式
OLED_SDA_Mode(GPIO_Mode_OUT);
OLED_SCLK = 1; //时钟线先拉高,数据线后拉高,即为停止信号
OLED_SDA_W = 0;
delay_us(1);
OLED_SDA_W = 1;
delay_us(1);
}
uint8_t IIC_Wait_Ack(void)
{
uint8_t ack=0;
//保证SDA引脚为输入模式
OLED_SDA_Mode(GPIO_Mode_IN);
OLED_SCLK = 1;
delay_us(1);
//有应答为低电平,无应答为高电平
if(OLED_SDA_R) //无应答
{
ack=1;
IIC_Stop();
}
else //有应答
ack=0;
OLED_SCLK = 0;
delay_us(1);
return ack;
}
/**********************************************
// IIC Read byte
**********************************************/
uint8_t i2c_recv_byte(void)
{
uint8_t byte=0;
uint32_t i=0;
//保证SDA引脚为输出模式
i2c_sda_mode(GPIO_Mode_OUT);
//设置为低电平
SCL=0;
SDA_W=0;
delay_us(5);
//保证SDA引脚为输入模式
i2c_sda_mode(GPIO_Mode_IN);
for(i=0; i<8; i++)
{
//设置时钟为高电平,告诉从机,可以对SDA引脚进行控制
SCL=1;
delay_us(5);
//读取SDA引脚的电平
if(SDA_R)
byte|=1<<(7-i);
//设置时钟为低电平,告诉从机,不可以对SDA引脚进行控制
SCL=0;
delay_us(5);
}
return byte;
}
void at24c02_read(uint8_t addr,uint8_t *pbuf,uint32_t len) //从机读取数据
{
uint32_t ack=0;
//发送起始信号
i2c_start();
//发送寻址地址
i2c_send_byte(0xA0);
//等待应答
ack=i2c_wait_ack();
if(ack)
{
printf("i2c ack device address failrn");
return ;
}
printf("i2c ack device address okrn");
//发送24c02的数据存储地址
i2c_send_byte(addr);
//等待应答
ack=i2c_wait_ack();
if(ack)
{
printf("i2c ack word address failrn");
return ;
}
printf("i2c ack word address okrn");
//再一次发送起始信号
i2c_start();
//发送寻址地址,读访问操作
i2c_send_byte(0xA1);
//等待应答
ack=i2c_wait_ack();
if(ack)
{
printf("i2c ack device address_r failrn");
return ;
}
printf("i2c ack device address_r okrn");
len=len-1;
while(len--)
{
*pbuf++=i2c_recv_byte();
i2c_ack(0);
}
*pbuf=i2c_recv_byte();
i2c_ack(1);
//发送停止信号
i2c_stop();
printf("i2c ack read data okrn");
}
/**********************************************
// IIC Write byte
**********************************************/
void Write_IIC_Byte(unsigned char IIC_Byte)
{
unsigned char i;
//保证SDA引脚为输出模式
OLED_SDA_Mode(GPIO_Mode_OUT);
OLED_SCLK = 0;
delay_us(1);
for(i=0;i<8;i++)
{
if(IIC_Byte&(1<<(7-i))) MSB
OLED_SDA_W = 1;
else
OLED_SDA_W = 0;
delay_us(1);
OLED_SCLK = 1;
delay_us(1);
OLED_SCLK = 0;
delay_us(1);
}
}
史海拾趣
|
CPU315-PN/DP连接3个分布式I/O机架,3个分布式I/O机架还未上电,直接给CPU的机架上电后程序下载正常,而且第一次下载采用TCP/IP的形式,后来发现AI模块的信号与现场设备的不符,现场的设备是4-20mA的信号输出,AI模块上设置的是0-10V的信号输入,AI ...… 查看全部问答> |
|
在编程中遇到个问题,LINUX下如何将字符串转化成UNICODE串以及将UNICODE串转换成字符串。 在WINDOWS下可以调用MultiByteToWideChar(),WideCharToMultiByte()函数完成, 请问LINUX下有类似的函数吗,网上说的不清楚,请高人指点.… 查看全部问答> |
|
刚学,也许问题就问得不对。见谅 如果GSM模块已经和计算机串口相连,网上有一段话说。 1) 从串口输入:AT+CMGS=”13636371111” 然后按回车键。 这里的 从串口输入 是指从哪里输入,是指用cmd命令进入DOS模式,在DOS ...… 查看全部问答> |
|
刚看见有人说430单片机很贵,100美金什么的,这可能是被AVR的代理商给忽悠过吧。 第一,430的产品齐全,价格一直在降,最近我申请了大概0.5美金的样片。反观AVR的芯片最近呢几年来一直在涨,现在很多芯片又是断货又是涨价的,很多芯片都不 ...… 查看全部问答> |
|
void Show_Waveform(void){ unsigned char k; unsigned int i,s; for(s=10;s<310;s++) { Set_ramaddr(cl[s-10],s); Write_com_data(0x0022,0x0000); if(cl[s-10]<c ...… 查看全部问答> |
|
$(\'swf_Jwj\').innerHTML=AC_FL_RunContent(\'width\', \'550\', \'height\', \'400\', \'allowNetworking\', \'internal\', \'allowScriptAccess\', \'never\', \'src\', encodeURI(\'http://player.youku.com/player.php/sid/XMzA3OTU5NTY4/v.sw ...… 查看全部问答> |




