单片机
返回首页

linux之I2C裸机驱动解析

2024-07-19 来源:cnblogs

1 硬件特性

1.1 概述


I2C总线是由Philips公司开发的两线式串行总线,这两根线为时钟线(SCL)和双向数据线(SDA)。由于I2C总线仅需要两根线,因此在电路板上占用的空间更少,带来的问题是带宽较窄。I2C在标准模式下传输速率最高100Kb/s,在快速模式下最高可达400kb/s。属于半双工。


在嵌入式系统中,I2C应用非常广泛,大多数微控制器中集成了I2C总线,一般用于和RTC,EEPROM,智能电池电路,传感器,LCD以及其他类似设备之间的通信。


1.2 I2C总线传输时序


1.3 I2C总线的信号状态


1、空闲状态:SDA和SCL都是高电平;


2、开始条件(S):SCL为高电平时,SDA由高电平向低电平跳变,开始传输数据;


3、结束条件(P):SCL为高电平时,SDA由低电平向高电平跳变,结束传输数据;


4、数据有效:在SCL的高电平期间,SDA保持稳定,数据有效。SDA的改变只能发生在SCL的低电平期间;


5、CK信号:数据传输的过程中,接收器件每接收一个字节数据要产生一个ACK信号,向发送器件发出特定的低电平脉冲,表示已经收到数据。


1.4 从设备地址


I2C总线从设备使用7位地址,最后一个为读写控制位。下图是eeprom的原理图,我们可以计算出它的地址为0x50。


1.5 I2C读写方式


多字节写的时序


多字节读的时序



具体可参考datasheet


附:ok6410裸机I2C代码。


  1 #define INTPND (*(volatile unsigned long*)0x4a000010)

  2 #define SRCPND (*(volatile unsigned long*)0x4a000000)

  3 #define INTMSK (*(volatile unsigned long*)0x4a000008)

  4 #define GPECON (*(volatile unsigned long*)0x56000040)

  5 #define GPEUP  (*(volatile unsigned long*)0x56000048)

  6 

  7 #define IICCON    (*(volatile unsigned char*)0x54000000)

  8 #define IICSTAT   (*(volatile unsigned char*)0x54000004)

  9 #define IICDS     (*(volatile unsigned char*)0x5400000C)

 10 

 11 #define SLAVE_WRITE_ADD 0xa0  /* 写入数据时;方向位(第0位)为0 */

 12 #define SLAVE_READ_ADD 0xa1   /* 读取数据时;方向位(第0位)为1 */

 13 

 14 

 15 void delay(int i)

 16 {

 17    int j = 0;

 18    while (i--)    

 19    {

 20        for (j=0;j<100;j++)

 21        {    

 22            ;

 23        }  

 24    }    

 25 }

 26 

 27 

 28 void i2c_init()

 29 {

 30     //1.a 初始化中断

 31     INTPND |= (1<<27);

 32     SRCPND |= (1<<27);  

 33     INTMSK &= ~(1<<27);

 34      

 35     IICCON |= (1<<5); 

 36     

 37     //1.b 设置scl时钟

 38     IICCON &= ~(1<<6);

 39     IICCON &= ~(0xf<<0);

 40     IICCON |= (0x5<<0);

 41     

 42     //2. 设置IICSTAT    

 43     IICCON |= (1<<4);

 44     

 45     //3.设置引脚功能

 46     GPECON |= (0x2<<28)|(0x2<<30);

 47     GPEUP |= (0x3<<14);

 48     

 49     //4.允许产生ACK

 50     IICCON |= (1<<7);

 51 }

 52 

 53 

 54 void write_byte(unsigned char xchar, unsigned char daddr)  

 55 {

 56     /* 写入数据时,每发送一个数据收到一个ACK就产生一次中断

 57      * 写入下次发送的数据之后要清除中断                      */

 58 

 59     //1. 设置处理器为主设备+发送模式

 60     IICSTAT |= (3<<6);

 61     

 62     //2. 将从设备的地址写入到IICDS寄存器

 63     IICDS = SLAVE_WRITE_ADD;

 64 

 65     //清除中断

 66     IICCON &= ~(1<<4);

 67     

 68     //3. 写入0xF0写入IICSTAT M/T Start

 69     IICSTAT = 0xF0;

 70     

 71     //4. 等待ACK的产生

 72     while ((IICCON & (1<<4)) == 0 )

 73         delay(100);

 74     

 75     //5.1写入字节的地址到IICDS寄存器

 76     IICDS = daddr;

 77 

 78 

 79     //5.2清除中断

 80      IICCON &= ~(1<<4);   

 81 

 82     //5.3等待ACK的产生

 83     while ((IICCON & (1<<4)) == 0 )

 84         delay(100);

 85     

 86     //6. 将要传输的字节数据写入IICDS寄存器

 87     IICDS = xchar;

 88 

 89     //7. 清除中断

 90     IICCON &= ~(1<<4);  

 91     

 92     //8. 等待ACk的产生

 93     while ((IICCON & (1<<4)) == 0 )

 94         delay(100);

 95     

 96     //9. 写入0xD0到IICSTAT

 97     IICSTAT = 0xD0;

 98     

 99     //10. 清除中断    

100     IICCON &= ~(1<<4);    

101     

102     delay(100);

103 }

104 

105 void read_data(unsigned char *buf, unsigned char daddr, int length) /* 结合eeprom手册 */

106 {

107     /* 每接收一个数据产生一个中断 */

108 

109     int j =0;

110     unsigned char unusedata;

111     

112     //1. 设置处理器为主设备+发送模式

113     IICSTAT |= (3<<6);

114     

115     //2. 将从设备的地址写入到IICDS寄存器

116     IICDS = SLAVE_WRITE_ADD;

117 

118     //清除中断

119     IICCON &= ~(1<<4);

120     

121     //3. 写入0xF0写入IICSTAT M/T-Start

122     IICSTAT = 0xF0;

123     

124     //4. 等待ACK的产生

125     while ((IICCON & (1<<4)) == 0 )

126         delay(100);

127     

128     //5.1写入eeprom内部地址

129     IICDS = daddr;

130 

131 

132     //5.2清除中断

133      IICCON &= ~(1<<4);   

134 

135     //5.3等待ACK的产生

136     while ((IICCON & (1<<4)) == 0 )

137         delay(100);

138 

139     /**************eeprom代码**************/

140     /**************************************/

141     /***************i2c代码****************/

142 

143     //设置为主设备接收模式

144     IICSTAT &= ~(3<<6);

145     IICSTAT |= (2<<6);

146     

147     

148     //2.写入从设备地址到IICDS  /* 从设备地址成功发送之后产生中断,故要清除中断 */

149     IICDS = SLAVE_READ_ADD;

150     //清除中断

151     IICCON &= ~(1<<4);

152     

153     

154     //3.写入0xB0到IICSTAT开始接收,每接收道一个数据就产生一个中断

155     IICSTAT = 0xb0;

156 

157     //等待中断

158     while ((IICCON & (1<<4)) == 0 )

159         delay(100);

160         

161 #if 0   

162     /***写入设备内部地址***/

163     IICDS = daddr;

164     IICCON &= ~(1 << 4);

165     while((IICCON & (1 << 4)) == 0)

166     {

167         delay(100);

168     }    

169 #endif 

170     

171     //***丢掉收到的第1个字节  第一个数据无效 丢弃!

172     unusedata = IICDS;

173     IICCON &= ~(1<<4);

174     while ((IICCON & (1<<4)) == 0 )

175             delay(100);

176     

177 

178 

179     for(j=0;j

180     {

181         if(j == (length - 1))

182         {

183            IICCON &= ~(1<<7);         

184         }

185    

186     //5.1 从IICDS里取出数据

187         buf[j]=IICDS;

188     

189     //5.2 清除中断

190         IICCON &= ~(1<<4);

191     

192     //4.等待中断

193         while ((IICCON & (1<<4)) == 0 )

194             delay(100);

195     }

196         

197         

198     //写入0x90到IICSTAT

199     IICSTAT = 0x90;

200     

201  

202     // 清除中断

203     IICCON &= ~(1<<4);

204 }

205 

206 void i2c_test()

207 {

208     int i=0;

209     unsigned char sbuf[256]={0};

210     unsigned char dbuf[256]={0};    

211     

212     i2c_init();

213     

214     for(i=0;i<256;i++)

215     {

216         sbuf[i] = i+1;

217         dbuf[i] = 0;

218     }

219     

220     printf('dbuf befor I2C read:rn');   

221     for(i =0; i<256;i++)

222     {

223        if(i%8==0)

224            printf('rn');  /*  */

225            

226        printf('%dt',dbuf[i]);    /*t-空格 */

227     }    

228      

229     for(i=0;i<256;i++)

230         write_byte(sbuf[i],i);

231         

232     printf('i2c reading, plese wait!nr');

233     

234     read_data(dbuf,0,256);

235     

236     printf('dbuf after I2C read:rn');

237     

238     for(i =0; i<256;i++)

239     {

240        if(i%8==0)

241            printf('rn');

242            

243        printf('%dt',dbuf[i]);    

244     }    

245 }


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

  • SOC系统级芯片设计实验

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

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

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

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

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 红外线探测报警器

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 开关电源的基本组成及工作原理

  • 带有短路保护系统的5V直流稳压电源电路图

    相关电子头条文章