gpio模拟i2c驱动

前段时间做项目,需要gpio模拟i2c通信,最后参考了一些资料,然后编写了一个程序。现在发出来,以免以后忘记,也为一些需要的朋友提供参考。不喜勿喷哈。

/* 说明:该程序是基于atmel公司的sama5d35 MCU 用其中两个GPIO引脚模拟i2c通信。
* 其中两个引脚连接到了hd1650上面。然后检测按键扫描的驱动
* */

该程序可以作为gpio模拟i2c程序的参考。不同的平台,函数实现不同,但是i2c通信的时序和原理是相同的。希望对一些朋友有帮助。

  1 #include<linux/init.h>
  2 #include<linux/module.h>
  3 #include<linux/kernel.h>
  4 #include<linux/sched.h>
  5 #include<linux/init.h>
  6 #include<linux/sched.h>
  7 #include<linux/completion.h>
  8 #include <asm/system.h>
  9 #include <linux/param.h>
 10 #include<linux/gpio.h>
 11 #include<linux/cdev.h>
 12 #include<linux/fs.h>
 13 #include<linux/device.h>
 14 #include<linux/slab.h>
 15 #include<asm/uaccess.h>
 16 #include<linux/delay.h>
 17 #include<linux/miscdevice.h>
 18
 19
 20
 21
 22 /* 定义GPIO引脚值,这个在内核里面有定义 */
 23 #define GPIO_PC30 94
 24 #define GPIO_PC31 95
 25
 26
 27 /* 定义GPIO引脚结构体,用于和上层进行通信 */
 28 typedef struct gpio_ctrl_blk{
 29     int pin;
 30     int value;
 31 }gpio_cblk_t;
 32
 33
 34 #define HD1650_DEV_ID ‘k‘
 35 #define GET_KEY             _IOWR (HD1650_DEV_ID,0x34,int)
 36
 37
 38 /* 定义延时函数,用于i2c通信 */
 39 #define DELAY_BUILD()    udelay(10)
 40 #define DELAY()            udelay(10)
 41
 42 /* this define copy from datasheet */
 43 #define CMD_SYSOFF    0x4800
 44 #define CMD_SYSON    0x4801
 45 #define CMD_SLEEPOFF    0x4800
 46 #define CMD_SLEEPON    0x4804
 47 #define CMD_7SEGON    0x4809
 48 #define CMD_8SEGON    0x4801
 49
 50 #define CMD_7SEGON1    0x4819
 51 #define CMD_7SEGON2    0x4829
 52 #define CMD_7SEGON3    0x4839
 53 #define CMD_7SEGON4    0x4849
 54 #define CMD_7SEGON5    0x4859
 55 #define CMD_7SEGON6    0x4869
 56 #define CMD_7SEGON7    0x4879
 57 #define CMD_7SEGON8    0x4809
 58
 59 #define CMD_8SEGON1    0x4811
 60 #define CMD_8SEGON2    0x4821
 61 #define CMD_8SEGON3    0x4831
 62 #define CMD_8SEGON4    0x4841
 63 #define CMD_8SEGON5    0x4851
 64 #define CMD_8SEGON6    0x4861
 65 #define CMD_8SEGON7    0x4871
 66 #define CMD_8SEGON8    0x4801
 67
 68 #define CMD_DIG0(x)    0x6800 | (x)
 69 #define CMD_DIG1(x)    0x6A00 | (x)
 70 #define CMD_DIG2(x)    0x6C00 | (x)
 71 #define CMD_DIG3(x)    0x6E00 | (x)
 72 #define CMD_GETKEY    0x4F00
 73
 74 /*show define*/
 75 /******************************************************************
 76   a
 77   __
 78 f|__|b
 79 e|__|c .dop  中间那段为g
 80 d
 81 *******************************************************************/
 82
 83 //数码管末一段的值
 84 #define BA        0x1
 85 #define BB        0x1<<1
 86 #define BC        0x1<<2
 87 #define BD        0x1<<3
 88 #define BE        0x1<<4
 89 #define BF        0x1<<5
 90 #define BG        0x1<<6
 91 #define BP        0x1<<7
 92
 93 //数码管显示的字符的值
 94 #define TM_A        BF | BA | BB | BG | BE | BC
 95 #define TM_B        BF | BE | BG | BD | BC
 96 #define TM_C        BG | BE | BD
 97 #define TM_D        BB | BC | BD | BE | BG
 98 #define TM_E        BA | BF | BG | BE | BD
 99 #define TM_G        BA | BF | BE | BD | BC
100 #define TM_F        BA | BF | BG | BE
101 #define TM_H        BF | BE | BG | BC
102 #define TM_I        BB | BC
103 #define TM_J        BB | BC | BD | BE
104 #define TM_K        BF | BG | BE | BC | BB
105 #define TM_L        BF | BE | BD
106 #define TM_M        0
107 #define TM_N        BE | BG | BC
108 #define TM_O        BG | BC | BD | BE
109 #define TM_P        BA | BB |BG | BF |BE
110 #define TM_Q        BF | BA | BB | BG | BC
111 #define TM_R        BE | BG
112 #define TM_S        BA | BF | BG | BC | BD
113 #define TM_T        BF | BG | BE | BD
114 #define TM_U        BF | BE | BD | BC | BB
115 #define TM_V        BE | BD | BC
116 #define TM_W        0
117 #define TM_X        0
118 #define TM_Y        0
119 #define TM_Z        0
120
121 #define TM_0        BA | BB | BC | BD | BE | BF
122 #define TM_1        BB | BC
123 #define TM_2        BA | BB | BG | BE | BD
124 #define TM_3        BA | BB | BC | BD | BG
125 #define TM_4        BF | BG | BB | BC
126 #define TM_5        BA | BF | BG | BC | BD
127 #define TM_6        BA | BF | BG | BE | BD | BC
128 #define TM_7        BF | BA | BB | BC
129 #define TM_8        BA | BB | BC | BD | BE | BF | BG
130 #define TM_9        BA | BB | BC | BD | BG | BF
131
132 unsigned char TM_NUM[] = {TM_0, TM_1, TM_2, TM_3, TM_4,
133 TM_5, TM_6, TM_7, TM_8, TM_9}; //定义键值
134
135 unsigned char TM_CHAR[] = {TM_A, TM_B, TM_C, TM_D, TM_E, TM_F, TM_G,
136 TM_H, TM_I, TM_J, TM_K, TM_L, TM_M, TM_N,
137 TM_O, TM_P, TM_Q, TM_R, TM_S, TM_T, TM_U,
138 TM_V, TM_W, TM_X, TM_Y, TM_Z};
139
140
141 /*对i2c操作函数*/
142 static void i2c_start(void);
143 static void i2c_stop(void);
144 static void i2c_send(unsigned char data);
145 static unsigned char i2c_recv(unsigned char *data);
146 static int i2c_get_ack(void);
147 static int i2c_get_ack_getkey(void);
148
149
150 static void CLK_OUT(void);
151 static void SDA_IN(void);
152 static void SDA_OUT(void);
153 static int GET_SDA(void);
154 static void CLK_H(void);
155 static void CLK_L(void);
156 static void SDA_H(void);
157 static void SDA_L(void);
158
159 static unsigned char hd1650_sendcmd(unsigned short cmd);
160
161
162 /*************函数实现******************/
163
164
165 /* 设置时钟引脚为输出引脚 */
166 static void CLK_OUT(void)
167 {
168     gpio_cblk_t gpio_dev;
169     gpio_dev.pin = GPIO_PC31;
170     gpio_dev.value = 1;
171
172     at91_set_gpio_output(gpio_dev.pin,gpio_dev.value);
173 }
174
175 /* 设置数据引脚为输出引脚 */
176 static void SDA_OUT(void)
177 {
178     gpio_cblk_t gpio_dev;
179
180     gpio_dev.pin = GPIO_PC30;
181     gpio_dev.value = 1;
182
183     at91_set_gpio_output(gpio_dev.pin,gpio_dev.value);
184 }
185
186 /* 设置数据引脚为输入引脚 */
187 static void SDA_IN(void)
188 {
189     gpio_cblk_t gpio_dev;
190
191     gpio_dev.pin = GPIO_PC30;
192     gpio_dev.value = 1;
193
194     at91_set_gpio_input(gpio_dev.pin,gpio_dev.value);
195 }
196
197 /* 取数据引脚的值 */
198 static int GET_SDA(void)
199 {
200     gpio_cblk_t gpio_dev;
201
202     gpio_dev.pin = GPIO_PC30;
203     gpio_dev.value = at91_get_gpio_value(gpio_dev.pin);
204
205     return gpio_dev.value;
206 }
207
208 /* 设置时钟引脚为高 */
209 static void CLK_H(void)
210 {
211     gpio_cblk_t gpio_dev;
212     gpio_dev.pin = GPIO_PC31;
213     gpio_dev.value = 1;
214
215     at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
216 }
217
218 /* 设置时钟引脚为低*/
219 static void CLK_L(void)
220 {
221     gpio_cblk_t gpio_dev;
222     gpio_dev.pin = GPIO_PC31;
223     gpio_dev.value = 0;
224
225     at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
226 }
227
228 /* 设置数据引脚为高 */
229 static void SDA_H(void)
230 {
231     gpio_cblk_t gpio_dev;
232     gpio_dev.pin = GPIO_PC30;
233     gpio_dev.value = 1;
234
235     at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
236 }
237
238 /* 设置数据引脚为低 */
239 static void SDA_L(void)
240 {
241     gpio_cblk_t gpio_dev;
242     gpio_dev.pin = GPIO_PC30;
243     gpio_dev.value = 0;
244
245     at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
246 }
247
248
249
250
251 /*****************************global function *********************************/
252 void hd1650_init(void)
253 {
254     hd1650_sendcmd(CMD_8SEGON);
255
256     /* clear 4 segment */
257     hd1650_sendcmd(CMD_DIG0(0x00));
258     hd1650_sendcmd(CMD_DIG1(0x00));
259     hd1650_sendcmd(CMD_DIG2(0x00));
260     hd1650_sendcmd(CMD_DIG3(0x00));
261 }
262
263 unsigned char asc2code(unsigned char src)
264 {
265
266     if(src <= 9)
267         return TM_NUM[src];
268     else if(src >= ‘0‘ && src <= ‘9‘)
269         return TM_NUM[src - ‘0‘];
270     else if(src >= ‘a‘ && src <= ‘z‘)
271         return TM_CHAR[src - ‘a‘];
272     else if(src >= ‘A‘ && src <= ‘Z‘)
273         return TM_CHAR[src - ‘A‘];
274     else
275         return 0;
276
277 }
278
279 /*data : 0-6
280  * pos: 2
281  * dot_flag:数码管的点的亮灭*/
282 void hd1650_show_each(unsigned char data, unsigned char pos,unsigned char dot_flag)
283 {
284     unsigned char tmpData;
285     //tmpData = asc2code(data);
286     switch(pos)
287     {
288         case 1:
289             hd1650_sendcmd(CMD_DIG0(tmpData));
290             break;
291         case 2:
292             if(dot_flag)
293                 hd1650_sendcmd(CMD_DIG1(tmpData|0x80));
294             else
295                 //hd1650_sendcmd(CMD_DIG1(tmpData&0x7f));
296                 hd1650_sendcmd(CMD_DIG1(data));
297             break;
298         case 3:
299             hd1650_sendcmd(CMD_DIG2(tmpData));
300             break;
301         case 4:
302             hd1650_sendcmd(CMD_DIG3(tmpData));
303             break;
304     }
305 }
306
307
308
309 unsigned char hd1650_getkey(unsigned char *key)
310 {
311     unsigned char tmp = 0;
312
313
314     tmp = hd1650_sendcmd( CMD_GETKEY );
315
316     if((tmp & 0x40)== 0)
317         tmp = 0x2e;
318
319     if( key )
320         *key = tmp;
321
322     return tmp;
323 }
324
325
326
327 /*****************************local function implemention*********************************/
328 /*****************************DO NOT MODIFY*********************************/
329 static void i2c_start(void)
330 {
331     CLK_OUT();
332     SDA_OUT();
333
334     SDA_H();
335     DELAY();
336     CLK_H();
337     DELAY_BUILD();
338     SDA_L();
339     DELAY();
340 }
341
342 static void i2c_stop(void)
343 {
344     SDA_OUT();
345     SDA_L();
346     DELAY();
347
348     CLK_H();
349     DELAY_BUILD();
350     SDA_H();
351     DELAY();
352
353
354 }
355
356 /* MSB */
357 static void i2c_send(unsigned char data)
358 {
359     unsigned char i = 0;
360     for(; i < 8 ; i++)
361     {
362         CLK_L();
363         DELAY_BUILD();
364         if( data & 0x80 )
365             SDA_H();
366         else
367             SDA_L();
368         data <<= 1;
369         DELAY();
370         CLK_H();
371         DELAY();
372     }
373 }
374
375 static unsigned char i2c_recv(unsigned char *data)
376 {
377     unsigned char i = 0, tmp=0;
378     SDA_IN();
379     for(; i < 8 ; i++)
380     {
381         CLK_L();
382         DELAY();
383         CLK_H();
384         DELAY_BUILD();
385         tmp <<= 1;
386         tmp |= GET_SDA();
387
388         DELAY();
389     }
390     SDA_OUT();
391
392     if( data )
393         *data = tmp;
394     return tmp;
395 }
396
397 static int i2c_get_ack(void)
398 {
399     int i = 30;
400
401     CLK_L();
402     SDA_IN();
403     DELAY_BUILD();
404
405     CLK_H();
406     DELAY();
407     while(GET_SDA() && i-- );
408     CLK_L();
409     SDA_OUT();
410
411     return 1;/*!!!Fixme. this should return the right value, but sometimes the ack cannot get */
412 }
413
414 static int i2c_get_ack_getkey(void)
415 {
416     int i = 30;
417
418     CLK_L();
419     SDA_IN();
420     DELAY_BUILD();
421
422     CLK_H();
423     DELAY();
424     while(!GET_SDA() && i-- );
425     CLK_L();
426     SDA_OUT();
427
428     return 1;/*!!!Fixme. this should return the right value, but sometimes the ack cannot get */
429 }
430
431
432 static unsigned char hd1650_sendcmd(unsigned short cmd)
433 {
434     unsigned char tmp_data = cmd>>8;
435
436     i2c_start();
437     i2c_send(tmp_data);
438     if(1 != i2c_get_ack() )
439     {
440         /* printk some error
441         * hd1650 didnot send the ack
442         */
443     }
444
445     if( cmd == CMD_GETKEY )
446     {
447         i2c_recv(&tmp_data);
448         if(1 != i2c_get_ack_getkey())
449         {
450             /* printk some error
451             * hd1650 didnot send the ack
452             */
453         }
454     }else{
455         tmp_data = cmd&0x0ff;
456         i2c_send(tmp_data);
457         if(1 != i2c_get_ack())
458         {
459             /* printk some error
460             * hd1650 didnot send the ack
461             */
462         }
463     }
464
465
466     i2c_stop();
467
468     return tmp_data;/* just valid for the CMD_GETKEY */
469 }
470
471
472
473
474 /*******END OF THE FILE *********/
475
476 static int hd1650_ctrl_drv_open(struct node *node, struct file *file )
477 {
478     return 0;
479 }
480
481 static int hd1650_ctrl_drv_release(struct node *node, struct file *file )
482 {
483     return 0;
484 }
485
486 static long hd1650_ctrl_drv_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
487 {
488     unsigned char key = 0;
489
490     int ret = 0;
491
492     switch (cmd) {
493     case GET_KEY:
494             hd1650_getkey(&key);
495             ret = put_user(key,(int *)arg);
496             break;
497     default:
498         return -EINVAL;
499
500     }
501
502
503
504     return 0;
505 }
506
507 static struct file_operations hd1650_ctl_drv_fileops = {
508     .owner = THIS_MODULE,
509     .open = hd1650_ctrl_drv_open,
510     .unlocked_ioctl = hd1650_ctrl_drv_unlocked_ioctl,
511     .release = hd1650_ctrl_drv_release
512 };
513
514 static struct miscdevice hd1650_dev = {
515     MISC_DYNAMIC_MINOR,
516     "hd1650_dev",
517     &hd1650_ctl_drv_fileops,
518 };
519 int gpio_ctrl_drv_module_init(void)
520 {
521     int ret = 0;
522
523
524     ret = misc_register(&hd1650_dev);
525     if(ret != 0)
526     {
527         ret = -EFAULT;
528         return ret;
529     }
530     hd1650_init();
531     hd1650_show_each(0x40 ,2,0);
532     printk("hd1650_drv_init ok\n");
533     return 0;
534 }
535
536
537 void gpio_ctrl_drv_module_exit(void)
538 {
539
540     misc_deregister(&hd1650_dev);
541     printk("gpio_drv_exit ok\n");
542 }
543
544
545
546 module_init(gpio_ctrl_drv_module_init);
547 module_exit(gpio_ctrl_drv_module_exit);
548 MODULE_LICENSE("GPL");
时间: 2024-10-07 06:33:09

gpio模拟i2c驱动的相关文章

S5PV210之GPIO模拟I2c时序之pcf8591与at24xx linux3.0.8驱动

目录:一. 说明 二. 驱动程序说明及问题 三. 案例一       四. 案例二 一. 说明 mini210开发板上带了at24c08, 看了linux内核自带的at24.c的驱动程序,编译下载到看发板,读写都行:通过增加一些调试信息,对linux i2c驱动其中的编写方法之一有了一定了解,在我的另外一篇博文有详细说明.但同时对在linux下GPIO模拟i2c产生了兴趣,于是就写这篇博文来记录驱动编写过程中遇到的问题.如果想了解了i2c时序,请google或百度一下. 本篇博文通过misc驱动

GPIO模拟I2C

之前在学习I2C驱动,想了想应该先深刻理解下I2C协议.个人觉得理解I2C协议最好的方法就是实践,而最好的实践方式就是用GPIO来模拟I2C协议进行试验,直观深刻. 先看下I2C时序图: 根据时序图,用两个gpio分别模拟sda和scl即可.在这之前自然需要先对gpio进行输入输出的配置.这里只从写数据角度来描述这一过程.读数据同理即知. 先配置gpio,包括sda.scl.供电gpio等额外功能gpio. gpio_config(GPIO_SDA, GPIO_OUTPUT); gpio_con

STM32F207 两路ADC连续转换及GPIO模拟I2C给Camera Sensor初始化参数

1.为了更好的方便调试,串口必须要有的,主要打印一些信息,当前时钟.转换后的电压值和I2C读出的数据. 2.通过GPIO 模拟I2C对镁光的MT9V024进行参数初始化.之前用我以前公司SP0A19芯片,是I2C是8位宽的,而镁光的地址是8位,而数据位是16个字节, 其实不管是8位还是16位,每次发送都是8个字节然后一个应答位,所以只要稍微改下代码即可. 3.实现两路ADC连续转换,两路ADC转换:一路是检测锂电池电压:一路是检测压力传感器,其实都是检测电压,当检测到压力为零,并累计多长时间后进

触摸按键--模拟I2C驱动TS12芯片

TS12芯片驱动 使用模拟I2C驱动TS12完成触摸按键检测功能: #include "stm8s.h" #include "global.h" #include "drv_key.h" uint8_t KeyByte; /******************************************************************************* // Function: I2C_Int // Descripti

【转载】GPIO模拟i2c通信

I2C总线的通信过程(见图4-8)主要包含三个主要阶段:起始阶段.数据传输阶段和终止阶段. 1. 起始阶段 在I2C总线不工作的情况下,SDA(数据线)和SCL(时钟线)上的信号均为高电平.如果此时主机需要发起新的通信请求,那么需要首先通过SDA和SCL发出起始标志.当SCL为高电平时,SDA电平从高变低,这一变化表示完成了通信的起始条件. 在起始条件和数据通信之间,通常会有延时要求,具体的指标会在设备厂商的规格说明书中给出. 2. 数据传输阶段 I2C总线的数据通信是以字节(8位)作为基本单位

gpio模拟I2C,驱动pcf8574T

一.pcf8574T介绍 查看pcf8574T的数据手册, A表示读或写,当A为1的时候表示读,当A为0的时候表示写.现把地址控制线,即A2.A1.A0全部接地,可以得到读控制指令为0x41,写控制指令为0x40. 二.I2C介绍 参考: http://blog.csdn.net/ce123_zhouwei/article/details/6882221 1.起始和停止时序 2.数据位的传输 也就是在SCL的下降沿将数据位传出. 3.主控制器为写的时候,接收应答 当传输完数据的第8位,第9位要发

Linux的i2c驱动详解

目录(?)[-] 简介 架构 设备注册 I2C关键数据结构和详细注册流程 关键数据结构 详细注册流程 使用I2C子系统资源函数操作I2C设备 Gpio模拟i2c总线的通用传输算法 总结 理清i2c中的个结构体关系 i2c驱动的编写建议 1 简介 I2C 总线仅仅使用 SCL . SDA 两根信号线就实现了设备之间的数据交互,极大地简化对硬件资源和 PCB 板布线空间的占用.因此, I2C 总线被非常广泛地应用在 EEPROM .实时钟.小型 LCD 等设备与 CPU 的接口中. Linux I2

Linux内核调用I2C驱动_以MPU6050为例

Linux内核调用I2C驱动_以MPU6050为例 0. 导语 最近一段时间都在恶补数据结构和C++,加上导师的事情比较多,Linux内核驱动的学习进程总是被阻碍.不过,十一假期终于没有人打扰,有这个奢侈的大块时间,可以一个人安安静静的在教研室看看Linux内核驱动的东西.按照Linux嵌入式学习的进程,SPI驱动搞完了之后就进入到I2C驱动的学习当中,十一还算是比较顺利,I2C的Linux驱动完成了. 为了测试I2C是否好用,选择一个常用的I2C传感器,手头有个MPU6050,刚好作为I2C的

GPIO模拟SPI

上次用gpio模拟i2c理解i2c协议,同样的,我用gpio模拟spi来理解spi协议. 我用的是4线spi,四线分别是片选.时钟.命令/数据.数据. 数据在时钟上升沿传递,数据表示的是数据还是命令由命令/数据线决定. 开始条件: void spi_start(void) { gpio_config(GPIO_CS, GPIO_OUTPUT); udelay(SPI_SPEED_DURATION); gpio_set(GPIO_CS, 0);/* start condition */ udela