[LKS32 软件]基于LKS081C8T8的IIC通讯发送与接收数据的实现

IIC通讯实验

1、实验概述  本实验通过两块LKS32MC081的demo板进行IIC通讯的发送和接收实验。实验使用P1.10作为SCL时钟信号线,P1.11作为SDA数据信号线,将两块081的核心板对应的P1.10与P1.11用杜邦线进行连接。由于IIC通讯需要进行上拉,因此需要在程序中对P1.10与P1.11进行开启上拉。081系列的IIC通讯不使用DMA进行搬运时需要利用IIC的中断进行判断,实现IIC的数据传输。

2、IIC通讯特点

  在物理连接上分别由 SDA(串行数据线)和 SCL(串行时钟线)及上拉电阻组成。通信原理是通过对 SCL和 SDA线高低电平时序的控制,来产生 IIC 总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平,否则无法输出高电平。
IIC 总线接口连接微控制器和串行 IIC 总线。它提供多主机功能,控制所有IIC总线特定的时序、协议、仲裁和定时。支持标准和快速两种模式。
IIC有以下特点:
①   IIC是半双工,而不是全双工;
②   IIC是真正的多主机总线,(对比SPI在每次通信前都需要把主机定死,而IIC可以在通讯过程中,改变主机),如果两个或更多的主机同时请求总线,可以通过冲突检测和仲裁防止总线数据被破坏;
③   起始和终止信号都是由主机发出的,连接到I2C总线上的器件,若具有IIC总线的硬件接口,则很容易检测到起始和终止信号;
④   在起始信号后必须发送一个7位从机地址+1位方向位,用“0”表示主机发送数据,“1”表示主机接收数据;
⑤   每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据;
⑥   起始信号是必需的,结束信号和应答信号,都可以不要。
注:实际使用中,一般是单片机作为主机,其它器件作为从机,单片机先向器件发送信息表示要读取数据,之后转变传输方向,器件发送数据到单片机。

图2.2  IIC传输时序图

  如图2.2所示为IIC基本的传输时序图,空闲状态时SCL与SDA均为高电平,在主机发出START信号后,SCL根据设定的波特率产生时钟信号,SDA首先输出7位从机地址+1位方向位,然后进行8位数据位的传输。需要注意的是,在一个字节传输的 8 个时钟后的第 9 个时钟期间,从机必须回送一个应答位(ACK)给发送器,每个字节后会跟随一个 ACK 信号。ACK bit使得接收者通知主机已经成功接收数据并准备接收下一个数据。当从机响应NACK信号后,判定为传输完成,主机产生STOP信号,完成一组信号的传输。 

3、程序配置3.1 主函数配置

在main函数中首先定义了发送数组I2C_TX_BUFF[8]与接收数组I2C_RX_BUFF[8],以及模式选择标志位Test_Pattern,0为发送接收轮流执行,1为仅发送,2为仅接收。
1.  u8 I2C_TX_BUFF[8] = {0x75,0x11,0x22,0x88,0x44,0x55,0x66,0x77};   
2.  u8 I2C_RX_BUFF[8] = {0};  
3.  u8 Test_Pattern = 2;  /*三种模式测试*/  
4.  int main(void)  
5.  {  
6.      Hardware_init();  
7.      while (1)  
8.      {  
9.          if(Test_Pattern == 0)/*发送接收;轮流执行*/  
10.         {  
11.             I2C_TX_Function(0x3C,I2C_TX_BUFF,8,I2C_TX_AND_RX);  
12.             I2C_RX_Function(0x3C,I2C_RX_BUFF,8,I2C_TX_AND_RX);  
13.         }  
14.      if(Test_Pattern == 1)/*只发送*/  
15.         {  
16.           I2C_TX_Function(0x3C,I2C_TX_BUFF,5,I2C_TX_OR_RX);  
17.         }  
18.      if(Test_Pattern == 2)/*只接收*/  
19.         {  
20.         I2C_RX_Function(0x3C,I2C_RX_BUFF,5,I2C_TX_OR_RX);  
21.         }  
22.         SoftDelay(100);  
23.     }  
24. }


3.2 GPIO配置

实验中使用 P1.10 为 SCL 时钟信号线,P1.11 为 SDA 数据信号线,将P1.10与P1.11配置为输入模式,在复用为IIC功能后,输入和输出模式会由IIC进行接管。
1.  void GPIO_init(void)  
2.  {  
3.      GPIO_InitTypeDef GPIO_InitStruct;  
4.      GPIO_StructInit(&GPIO_InitStruct);  
5.      GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;  
6.      GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10 |GPIO_Pin_11;  
7.      GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;//开启上拉,否则无法输出高电平  
8.      GPIO_Init (GPIO1,&GPIO_InitStruct);  
9.      GPIO_PinAFConfig(GPIO1,GPIO_PinSource_10,AF6_I2C );   //p1.10复用功能SCL
10.     GPIO_PinAFConfig(GPIO1,GPIO_PinSource_11,AF6_I2C );   //p1.11复用功能SDA
11. }  


3.3 IIC初始化配置

IIC硬件地址比较仅在使用DMA模式下开启才有效;初始化时 IIC 发送地址数据不进行配置,后续在发送函数进行配置;初始化主要开启 IIC 主模式使能,和IIC的时钟分频设置;然后就是使能 IIC的各种中断,使用主要用到 NACK,数据传输完成,停止时间(STOP)事件中断使能,总线错误中断。
在主机中将主模式ENABLE,从模式DISABLE,从机中将主模式DISABLE,从模式ENALBE。
1.  void I2C_init(u32 div0)  
2.  {  
3.      I2C_InitTypeDef I2C_InitStruct;  
4.      I2C_StructInit(&I2C_InitStruct);  
5.      I2C_InitStruct.ADRCMP           =   DISABLE ;   //  I2C 硬件地址比较使能开关
6.      I2C_InitStruct.MST_MODE         =   ENABLE  ;   //  I2C 主模式使能  
7.      I2C_InitStruct.SLV_MODE         =   DISABLE ;   //  I2C 从模式使能  
8.      I2C_InitStruct.DMA              =   DISABLE  ;  //  I2C DMA传输使能   
9.      I2C_InitStruct.BaudRate         =   div0 ;      //  I2C 波特率  
10.     I2C_InitStruct.IE               =   ENABLE  ;   //  I2C 中断使能  
11.     I2C_InitStruct.TC_IE            =   ENABLE  ;   //  I2C 数据传输完成中断使能  
12.     I2C_InitStruct.BUS_ERR_IE       =   DISABLE ;   //  I2C 总线错误事件中断使能  
13.     I2C_InitStruct.STOP_IE          =   ENABLE ;    //  I2C STOP 事件中断使能  
14.     I2C_InitStruct.BURST_NACK       =   ENABLE  ;   //  I2C 传输NACK 事件中断使能
15.     I2C_InitStruct.BURST_ADDR_CMP   =   DISABLE ;   //  硬件地址匹配中断使能  
16.     I2C_Init(I2C, &I2C_InitStruct);  
17.     I2C_Par.IIC_div_t = div0;//保存IIC波特率设置,在传输错误中断会重新硬件初始化
18.     I2C_Par.Idle_RX_Flag = 1;/* I2C接收时检查空闲标志位初始化*/  
19.     I2C_Par.Idle_TX_Flag = 1;/* I2C发送时检查空闲标志位初始化*/  
20. }


3.4 IIC发送函数配置

IIC发送函数最主要就是将 7bit 地址数据移位到高7位,最低位写0操作。对于数组传输的搬运判断处理在IIC中断函数内完成。当发送数据完成后,i2c_delay_txok()返回0,表示总线处于空闲状态,可以进行下一组数据的发送与接收,对所有中间状态变量进行复位操作。
1.  u8 I2C_TX_Function(u8 addr, u8 *i2c_data, u32 len, u8 mode)  
2.  {  
3.      I2C_Par.Tran_Mode = mode;       //发送模式确认  
4.      if (!i2c_delay_txok())          //等待I2C发送完成  
5.      {  
6.          I2C_Par.Data_Length_TX = len;  
7.          I2C_Par.I2C_DATA_TX = i2c_data;  
8.          I2C_Par.IIC_ADDR = addr << 1;  
9.          I2C_Par.Data_Temp_Length_TX = 0;  
10.         I2C0_DATA = I2C_Par.IIC_ADDR; // 地址信号  
11.         I2C0_MSCR |= BIT0;                // 触发I2C发送地址  
12.         I2C_Par.I2C_Mode = 0;             // 发送模式  
13.         return 0x0;                           // 发送成功  
14.     }  
15.     else  
16.     {  
17.         return 0xff; /*发送失败*/  
18.     }  
19. }


3.5 IIC接收函数配置

接收函数主要功能也是对地址的写入,先对 7bit 地址数据移位后最低为写 1 (表示接收数据),其它操作与发送函数一样。
1.  u8 I2C_RX_Function(u8 addr, u8 *i2c_data, u32 len, u8 mode)  
2.  {  
3.      I2C_Par.Tran_Mode = mode;  
4.      if (!i2c_delay_rxok())  
5.      {  
6.          I2C_Par.IIC_ADDR = addr << 1;  
7.          I2C_Par.Data_Length_RX = (len - 1);  
8.          I2C_Par.I2C_DATA_RX = i2c_data;  
9.          I2C_Par.Data_Temp_Length_RX = 0;  
10.         I2C0_DATA = I2C_Par.IIC_ADDR | 0x01; // 地址信号  
11.         I2C0_MSCR |= BIT0;                  // 触发I2C发送地址  
12.         I2C_Par.I2C_Mode = 1;               // 接收模式  
13.         return 0x0;                         // 发送成功  
14.     }  
15.     else  
16.     {  
17.         return 0xff; /*发送失败*/  
18.     }  
19. }  


3.6 IIC中断函数配置

IIC中断函数读取 I2C_SCR 寄存器,获得当前 I2C 总线状态及当前传输处于什么阶段,判断接下来需要进行的操作。
case0x01:接收模式,当接收未完成时,接收当前字节个数Data_Temp_Length_RX自加1,返回ACK信号给主机;当接收完成时,返回NACK信号给主机。
case0x05:如果第一个数据发送成功从设备返回 ACK 应答信号,则产生发送完成中断,在中断内判断I2C_SCR=0x05。数据触发发送,发送完成且接收到ACK信号,则对 I2C_DATA 写入下一字节发送数据,操作I2C_SCR的BIT2位触发发送数据,直到发送最后一个直接后清零I2C_SCR,硬件自动产生STOP信号。
case0x07:如果任意字节发送接收到NACK信号,就会进入I2C_SCR=0x07;软件对 I2C_SCR清零,然后产生STOP信号结束发送。
case0x09:用来判断数据发送完成且第一个发送字节为地址且接收到ACK应答,然后继续要发送数据第一个字节。若为发送模式,则将I2C_SCR寄存器的第二位DATA_DIR置1,触发发送功能;若为接收模式,将I2C_SCR寄存器的第二位DATA_DIR置0,触发接收功能。
case0x20:根据不同模式对发送状态变量和接收状态变量置1,该变量主要用于在执行 I2C_TX_Function()和 I2C_RX_Function()函数时判断IIC总线是否空闲,如果置1表示总线空闲,可以进行地址数据的发送。
1.  void I2C0_IRQHandler(void)  
2.  {  
3.      switch (I2C0_SCR)  
4.      {     
5.      case 0x01: // byte complete  
6.          if (I2C_Par.Data_Temp_Length_RX >= I2C_Par.Data_Length_RX)  
7.          {  
8.              I2C_Par.I2C_DATA_RX[I2C_Par.Data_Temp_Length_RX] = I2C0_DATA;  
9.              I2C0_SCR = 0x00; //字节接收完成,返回 NACK 回应  
10.             break;  
11.         }  
12.         else  
13.         {  
14.         I2C_Par.I2C_DATA_RX[I2C_Par.Data_Temp_Length_RX] = I2C0_DATA;  
15.         I2C_Par.Data_Temp_Length_RX += 1;  
16.         I2C0_SCR = BIT4; //字节接收完成,返回 ACK 回应  
17.         break; }      
18.   
19.     case 0x05://发送模式 and I2C数据发送完成 且接收到ACK信号  
20.         if (I2C_Par.Data_Temp_Length_TX >= I2C_Par.Data_Length_TX) //传输最后1Byte数据I2C_Par.Data_Length  
21.         {  
22.             I2C0_SCR = 0x00; /*清零ACK,触发STOP信号*/  
23.             break;  
24.         }  
25.         else  
26.         {  
27.             I2C0_DATA = I2C_Par.I2C_DATA_TX[I2C_Par.Data_Temp_Length_TX]; //再次发送数据  
28.             I2C_Par.Data_Temp_Length_TX += 1;  
29.             I2C0_SCR = BIT2; /*触发I2C发送数据*/  
30.             break;  
31.         }  
32.   
33.     case 0x07: // 发送,字节完成和接收到NACK  
34.         /*发送模式,检查从机返回NACK,该内容根据实际情况进行处理*/  
35.         I2C0_SCR = 0x00;  
36.         break;  
37.      
38.     case 0x09:                 //当前传输为地址数据  
39.         if (!I2C_Par.I2C_Mode) //发送模式  
40.         {  
41.             I2C0_DATA = I2C_Par.I2C_DATA_TX[I2C_Par.Data_Temp_Length_TX]; // transmit first data  
42.             I2C_Par.Data_Temp_Length_TX += 1;  
43.             I2C0_SCR = BIT2; /*触发I2C发送数据*/  
44.         }  
45.         else  
46.         { //接收模式  
47.             I2C0_SCR = BIT0;  /*触发I2C接收数据*/   
48.         }  
49.         break;  
50.   
51.     case 0x0B: // 从地址不匹配;  
52.         /*检查从模式地址匹配错误事件,该内容根据实际情况进行处理*/  
53.         I2C0_SCR = 0x00;  
54.         break;  
55.   
56.     case 0x20: // stop;  
57.         if (I2C_Par.Tran_Mode == I2C_TX_OR_RX)  
58.         {  
59.             I2C_Par.Idle_TX_Flag = 1;  
60.             I2C_Par.Idle_RX_Flag = 1;  
61.         }  
62.         else if (I2C_Par.Tran_Mode == I2C_TX_AND_RX)  
63.         {  
64.             if (!I2C_Par.I2C_Mode) //发送模式  
65.             {  
66.                 I2C_Par.Idle_RX_Flag = 1;  
67.             }  
68.             else  
69.             {  
70.                 I2C_Par.Idle_TX_Flag = 1;  
71.             }  
72.         }  
73.         I2C0_SCR = 0x00;  
74.         break;  
75.     default:  
76.         I2C_init(I2C_Par.IIC_div_t); //传输错误,复位IIC  
77.         I2C0_SCR = 0x00;  
78.         break;  
79.     }  
80. }
1.   


4、硬件连接

利用两块LKS081C8T8demo板进行实验验证,一块作为主机发送数据,一块作为从机接收数据,将两块芯片的P1.10与P1.11引脚用杜邦线进行连接。

图4.1 实验硬件连接
5、实验验证
实验波形如下,发送数据数组定义为{0x75,0x11,0x22,0x88,0x44,0x55,0x66,0x77},主函数中发送数组中的前5位,如图5.1所示为示波器的实验波形,1通道为SCL信号,2通道为SDA信号,通过示波器的解码功能对波形进行IIC解码,可以看到接收数据为数组的前5位,实验功能可行。

图5.1 实验波形

---------------------
作者:ajzh
链接:https://bbs.21ic.com/icview-3302494-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值