单片机
返回首页

54。I2C通信实验

2018-10-17 来源:eefocus

C语言小知识:

如何定义字符串:

可以通过字符数组或字符指针来定义字符串,也可以用宏定义对常量字符串进行定义。

 //定义字符串的几种方式

char names2[ ] = 'jack';   字符串数组

char * names3 = 'jack';    字符串指针

字符串是按ASSII码表以十六进制码存储的,比如 W就是0x57, a就是0x61

注意:

声明存储字符串的数组时,数组大小至少比所存储的字符串多1,因为编译器会自动在字符串常量的末尾添加空字符\0。


一。IIC通信协议

(一)概述

54。I2C通信实验

IIC器件的连接方式

54。I2C通信实验
每个器件都有自己相应的地址。

IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。I2C 总线在传送数据过程中共有三种类型信号,  它们分别是:开始信号、结束信号和应答信号。

开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。

结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。

应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。 CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号, CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。

(二)IIC协议

54。I2C通信实验

1. 空闲状态

54。I2C通信实验
SCL和SDA分别接两个上拉电阻,以使IIC在空闲的时候为高电平。

2. 开始信号和停止信号

54。I2C通信实验

3. 应答信号

54。I2C通信实验
有效应答ACK必须在第9个时钟脉冲为高电平期间保持稳定,因此先要将SCL拉低,然后发出ACK信号,再拉高SCL,再把SCL拉低。

4. 数据的有效性

54。I2C通信实验
数据必须要在SCL为高电平期间保持稳定,因此要先把SCL拉低,然后发送数据,再把SCL拉高,再把SCL拉低,这样就保证了在SCL为高电平期间数据是稳定的,再把SCL拉低,在SCL为低电平期间数据才允许变化。

5. 数据传输

54。I2C通信实验

(三)IIC底层驱动程序

 

54。I2C通信实验

STM32 的 CRH 控制着每组 IO 端口(A~G)的高 8 位的模式。每个 IO 端口的位占用 CRL 的 4 个位,高两位为 CNF,低两位为 MODE。

 0X3 表示推挽输出模式(做输出口用,50M 速率)、0X8 表示上/下拉输入模式(做输入口用)。

myiic.h

//IO方向设置,控制IO工作模式

 

#define SDA_IN()   {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;}

#define SDA_OUT()  {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;}

//IO操作函数  

#define IIC_SCL    PBout(10) //SCL

#define IIC_SDA    PBout(11) //SDA  

#define READ_SDA   PBin(11)  //输入SDA 

myiic.c

//初始化IIC

void IIC_Init(void)

{     

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟

  

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11); //PB6,PB7 输出高,因为IIC总线在空闲是都为高电平

}

54。I2C通信实验

//产生IIC起始信号

void IIC_Start(void)

{

SDA_OUT();     //sda线输出

IIC_SDA=1;    

IIC_SCL=1;

delay_us(4);

  IIC_SDA=0;//START:when CLK is high,DATA change form high to low 

delay_us(4);

IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 

}

54。I2C通信实验

 

//产生IIC停止信号

void IIC_Stop(void)

{

SDA_OUT();//sda线输出

IIC_SCL=0;

IIC_SDA=0;//STOP:when CLK is high DATA change form low to high

  delay_us(4);

IIC_SCL=1; 

IIC_SDA=1;//发送I2C总线结束信号

delay_us(4);  

}

54。I2C通信实验
要先把SCL拉低,然后准备好ACK应答数据,再拉高SCL,这样就可以保证在SCL为高电平期间ACK信号是稳定的。

//产生ACK应答,也就是有效应答

void IIC_Ack(void)

{

IIC_SCL=0;

SDA_OUT();

IIC_SDA=0;

delay_us(2);

IIC_SCL=1;

delay_us(2);

IIC_SCL=0;

}

//不产生ACK应答,无效应答    

void IIC_NAck(void)

{

IIC_SCL=0;

SDA_OUT();

IIC_SDA=1;

delay_us(2);

IIC_SCL=1;

delay_us(2);

IIC_SCL=0;

}

54。I2C通信实验
同样是先把SCL拉低,然后准备好数据,再拉高SCL,然后再拉低SCL,这样是为了保证在SCL为高电平期间数据是稳定的,数据只有在SCL为低电平时才允许改变。

//IIC发送一个字节

//返回从机有无应答

//1,有应答

//0,无应答  

void IIC_Send_Byte(u8 txd)

{                        

    u8 t;   

SDA_OUT();    

    IIC_SCL=0;//拉低时钟开始数据传输

    for(t=0;t<8;t++)

    {              

if((txd&0x80)>>7)  //判断数据最高位是不是1

IIC_SDA=1;    //是1 , SDA输出高

else

IIC_SDA=0;   //是0,SDA输出低

txd<<=1; //数据左移一位

 

delay_us(2);   //对TEA5767这三个延时都是必须的

IIC_SCL=1;

delay_us(2); 

IIC_SCL=0;

delay_us(2);

    }  

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   

u8 IIC_Read_Byte(unsigned char ack)

{

unsigned char i,receive=0;

SDA_IN();//SDA设置为输入


    for(i=0;i<8;i++ )

{

        IIC_SCL=0; 

        delay_us(2);

IIC_SCL=1;

        receive<<=1;

        if(READ_SDA)receive++;   

delay_us(1); 

    }  

    if (!ack)

        IIC_NAck();//发送nACK

    else

        IIC_Ack(); //发送ACK   

    return receive;

}

    

二。24C02操作

54。I2C通信实验
A0,A1,A2为地址线,确定IIC器件的地址

54。I2C通信实验
24C02容量为2K,A0,A1,A2都接地, 读为1,写为0

所以这里24C02读地址为 1010 0001,也就是A1,写地址为 1010 0000,也就是A0。

24cxx.c文件

初始化程序

//初始化IIC接口

void AT24CXX_Init(void)

{

IIC_Init();

}

写一个字节程序

54。I2C通信实验

//在AT24CXX指定地址写入一个数据

//WriteAddr  :写入数据的目的地址    

//DataToWrite:要写入的数据

void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)

{          

    IIC_Start();  

if(EE_TYPE>AT24C16)

{

IIC_Send_Byte(0XA0);    //发送写命令,这里24C02写地址为A0

IIC_Wait_Ack();

IIC_Send_Byte(WriteAddr>>8);//发送高地址

  }else

{

IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据,为了兼容其他型号                                                                                              的IIC芯片

}  

IIC_Wait_Ack();   

    IIC_Send_Byte(WriteAddr%6);   //发送低地址

IIC_Wait_Ack();     

IIC_Send_Byte(DataToWrite);     //发送字节   

IIC_Wait_Ack();         

    IIC_Stop();//产生一个停止条件 

delay_ms(10);  

}

读一个字节程序

54。I2C通信实验
前面一段为DUMMY WRITE,后面才读入一个DATA

//在AT24CXX指定地址读出一个数据

//ReadAddr:开始读数的地址  

//返回值  :读到的数据

u8 AT24CXX_ReadOneByte(u16 ReadAddr)

{  

u8 temp=0;        

    IIC_Start();  

if(EE_TYPE>AT24C16)

{

IIC_Send_Byte(0XA0);   //发送写命令

IIC_Wait_Ack();

IIC_Send_Byte(ReadAddr>>8);//发送高地址

IIC_Wait_Ack();  

}else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据,为了兼容其他型号                                                                                                 的IIC芯片  

IIC_Wait_Ack(); 

    IIC_Send_Byte(ReadAddr%6);   //发送低地址

IIC_Wait_Ack();    

IIC_Start();     

IIC_Send_Byte(0XA1);           //进入接收模式 ,这里24C02读地址为A1 

IIC_Wait_Ack();  

    temp=IIC_Read_Byte(0);   

    IIC_Stop();//产生一个停止条件    

return temp;

}

三。实验程序讲解

//要写入到24c02的字符串数组

const u8 TEXT_Buffer[]={'WarShipSTM32 IIC TEST'};  //定义一个字符串数组

#define SIZE sizeof(TEXT_Buffer) //SIZE为数组大小,比定义的数组大1,因为编译器自动在字符串结尾加了                                                           一个结束符 \0

 int main(void)

 {  

u8 a,key;

u16 i=0;

u8 datatemp[SIZE];

delay_init();     //延时函数初始化  

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级

uart_init(115200); //串口初始化为115200

LED_Init();   //初始化与LED连接的硬件接口

LCD_Init();   //初始化LCD

KEY_Init(); //按键初始化

AT24CXX_Init(); //IIC初始化 

  POINT_COLOR=RED;//设置字体为红色 

LCD_ShowString(30,50,200,16,16,'WarShip STM32');

LCD_ShowString(30,70,200,16,16,'IIC TEST');

LCD_ShowString(30,90,200,16,16,'ATOM@ALIENTEK');

LCD_ShowString(30,110,200,16,16,'2015/1/15');

LCD_ShowString(30,130,200,16,16,'KEY1:Write  KEY0:Read'); //显示提示信息

  while(AT24CXX_Check())//检测不到24c02

{

LCD_ShowString(30,150,200,16,16,'24C02 Check Failed!');

delay_ms(500);

LCD_ShowString(30,150,200,16,16,'Please Check!      ');

delay_ms(500);

LED0=!LED0;//DS0闪烁

}

LCD_ShowString(30,150,200,16,16,'24C02 Ready!');    

  POINT_COLOR=BLUE;//设置字体为蓝色

  

while(1)

{

key=KEY_Scan(0);

if(key==KEY1_PRES)//KEY_UP按下,写入24C02

{

LCD_Fill(0,170,239,319,WHITE);//清除半屏    

  LCD_ShowString(30,170,200,16,16,'Start Write 24C02....');

AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);  //写入字符串数组

LCD_ShowString(30,170,200,16,16,'24C02 Write Finished!');//提示传送完成

}

if(key==KEY0_PRES)//KEY1按下,读取字符串并显示

{

  LCD_ShowString(30,170,200,16,16,'Start Read 24C02.... ');

AT24CXX_Read(0,datatemp,SIZE);    //读出字符串数组

LCD_ShowString(30,170,200,16,16,'The Data Readed Is:  ');//提示传送完成

LCD_ShowString(30,190,200,16,16,datatemp);//显示读到的字符串

}

i++;

delay_ms(10);

if(i==20)

{

LED0=!LED0;//提示系统正在运行

i=0;

}   

}

}


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 光控音效发生器电路

  • 一个简单的警笛电路图

  • 优化电路板布局的简单方法

  • 一个简单的立体声平衡指示器电路

  • 分享一个电网倾角计电路

  • 使用NE555和磁簧开关的橱柜照明电路

    相关电子头条文章