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

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

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

 #include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/sched.h>
#include<linux/init.h>
#include<linux/sched.h>
#include<linux/completion.h>
#include <asm/system.h>
#include <linux/param.h>
#include<linux/gpio.h>
#include<linux/cdev.h>
#include<linux/fs.h>
#include<linux/device.h>
#include<linux/slab.h>
#include<asm/uaccess.h>
#include<linux/delay.h>
#include<linux/miscdevice.h> /* 定义GPIO引脚值,这个在内核里面有定义 */
#define GPIO_PC30 94
#define GPIO_PC31 95 /* 定义GPIO引脚结构体,用于和上层进行通信 */
typedef struct gpio_ctrl_blk{
int pin;
int value;
}gpio_cblk_t; #define HD1650_DEV_ID 'k'
#define GET_KEY _IOWR (HD1650_DEV_ID,0x34,int) /* 定义延时函数,用于i2c通信 */
#define DELAY_BUILD() udelay(10)
#define DELAY() udelay(10) /* this define copy from datasheet */
#define CMD_SYSOFF 0x4800
#define CMD_SYSON 0x4801
#define CMD_SLEEPOFF 0x4800
#define CMD_SLEEPON 0x4804
#define CMD_7SEGON 0x4809
#define CMD_8SEGON 0x4801 #define CMD_7SEGON1 0x4819
#define CMD_7SEGON2 0x4829
#define CMD_7SEGON3 0x4839
#define CMD_7SEGON4 0x4849
#define CMD_7SEGON5 0x4859
#define CMD_7SEGON6 0x4869
#define CMD_7SEGON7 0x4879
#define CMD_7SEGON8 0x4809 #define CMD_8SEGON1 0x4811
#define CMD_8SEGON2 0x4821
#define CMD_8SEGON3 0x4831
#define CMD_8SEGON4 0x4841
#define CMD_8SEGON5 0x4851
#define CMD_8SEGON6 0x4861
#define CMD_8SEGON7 0x4871
#define CMD_8SEGON8 0x4801 #define CMD_DIG0(x) 0x6800 | (x)
#define CMD_DIG1(x) 0x6A00 | (x)
#define CMD_DIG2(x) 0x6C00 | (x)
#define CMD_DIG3(x) 0x6E00 | (x)
#define CMD_GETKEY 0x4F00 /*show define*/
/******************************************************************
a
__
f|__|b
e|__|c .dop 中间那段为g
d
*******************************************************************/ //数码管末一段的值
#define BA 0x1
#define BB 0x1<<1
#define BC 0x1<<2
#define BD 0x1<<3
#define BE 0x1<<4
#define BF 0x1<<5
#define BG 0x1<<6
#define BP 0x1<<7 //数码管显示的字符的值
#define TM_A BF | BA | BB | BG | BE | BC
#define TM_B BF | BE | BG | BD | BC
#define TM_C BG | BE | BD
#define TM_D BB | BC | BD | BE | BG
#define TM_E BA | BF | BG | BE | BD
#define TM_G BA | BF | BE | BD | BC
#define TM_F BA | BF | BG | BE
#define TM_H BF | BE | BG | BC
#define TM_I BB | BC
#define TM_J BB | BC | BD | BE
#define TM_K BF | BG | BE | BC | BB
#define TM_L BF | BE | BD
#define TM_M 0
#define TM_N BE | BG | BC
#define TM_O BG | BC | BD | BE
#define TM_P BA | BB |BG | BF |BE
#define TM_Q BF | BA | BB | BG | BC
#define TM_R BE | BG
#define TM_S BA | BF | BG | BC | BD
#define TM_T BF | BG | BE | BD
#define TM_U BF | BE | BD | BC | BB
#define TM_V BE | BD | BC
#define TM_W 0
#define TM_X 0
#define TM_Y 0
#define TM_Z 0 #define TM_0 BA | BB | BC | BD | BE | BF
#define TM_1 BB | BC
#define TM_2 BA | BB | BG | BE | BD
#define TM_3 BA | BB | BC | BD | BG
#define TM_4 BF | BG | BB | BC
#define TM_5 BA | BF | BG | BC | BD
#define TM_6 BA | BF | BG | BE | BD | BC
#define TM_7 BF | BA | BB | BC
#define TM_8 BA | BB | BC | BD | BE | BF | BG
#define TM_9 BA | BB | BC | BD | BG | BF unsigned char TM_NUM[] = {TM_0, TM_1, TM_2, TM_3, TM_4,
TM_5, TM_6, TM_7, TM_8, TM_9}; //定义键值 unsigned char TM_CHAR[] = {TM_A, TM_B, TM_C, TM_D, TM_E, TM_F, TM_G,
TM_H, TM_I, TM_J, TM_K, TM_L, TM_M, TM_N,
TM_O, TM_P, TM_Q, TM_R, TM_S, TM_T, TM_U,
TM_V, TM_W, TM_X, TM_Y, TM_Z}; /*对i2c操作函数*/
static void i2c_start(void);
static void i2c_stop(void);
static void i2c_send(unsigned char data);
static unsigned char i2c_recv(unsigned char *data);
static int i2c_get_ack(void);
static int i2c_get_ack_getkey(void); static void CLK_OUT(void);
static void SDA_IN(void);
static void SDA_OUT(void);
static int GET_SDA(void);
static void CLK_H(void);
static void CLK_L(void);
static void SDA_H(void);
static void SDA_L(void); static unsigned char hd1650_sendcmd(unsigned short cmd); /*************函数实现******************/ /* 设置时钟引脚为输出引脚 */
static void CLK_OUT(void)
{
gpio_cblk_t gpio_dev;
gpio_dev.pin = GPIO_PC31;
gpio_dev.value = ; at91_set_gpio_output(gpio_dev.pin,gpio_dev.value);
} /* 设置数据引脚为输出引脚 */
static void SDA_OUT(void)
{
gpio_cblk_t gpio_dev; gpio_dev.pin = GPIO_PC30;
gpio_dev.value = ; at91_set_gpio_output(gpio_dev.pin,gpio_dev.value);
} /* 设置数据引脚为输入引脚 */
static void SDA_IN(void)
{
gpio_cblk_t gpio_dev; gpio_dev.pin = GPIO_PC30;
gpio_dev.value = ; at91_set_gpio_input(gpio_dev.pin,gpio_dev.value);
} /* 取数据引脚的值 */
static int GET_SDA(void)
{
gpio_cblk_t gpio_dev; gpio_dev.pin = GPIO_PC30;
gpio_dev.value = at91_get_gpio_value(gpio_dev.pin); return gpio_dev.value;
} /* 设置时钟引脚为高 */
static void CLK_H(void)
{
gpio_cblk_t gpio_dev;
gpio_dev.pin = GPIO_PC31;
gpio_dev.value = ; at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
} /* 设置时钟引脚为低*/
static void CLK_L(void)
{
gpio_cblk_t gpio_dev;
gpio_dev.pin = GPIO_PC31;
gpio_dev.value = ; at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
} /* 设置数据引脚为高 */
static void SDA_H(void)
{
gpio_cblk_t gpio_dev;
gpio_dev.pin = GPIO_PC30;
gpio_dev.value = ; at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
} /* 设置数据引脚为低 */
static void SDA_L(void)
{
gpio_cblk_t gpio_dev;
gpio_dev.pin = GPIO_PC30;
gpio_dev.value = ; at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
} /*****************************global function *********************************/
void hd1650_init(void)
{
hd1650_sendcmd(CMD_8SEGON); /* clear 4 segment */
hd1650_sendcmd(CMD_DIG0(0x00));
hd1650_sendcmd(CMD_DIG1(0x00));
hd1650_sendcmd(CMD_DIG2(0x00));
hd1650_sendcmd(CMD_DIG3(0x00));
} unsigned char asc2code(unsigned char src)
{ if(src <= )
return TM_NUM[src];
else if(src >= '' && src <= '')
return TM_NUM[src - ''];
else if(src >= 'a' && src <= 'z')
return TM_CHAR[src - 'a'];
else if(src >= 'A' && src <= 'Z')
return TM_CHAR[src - 'A'];
else
return ; } /*data : 0-6
* pos: 2
* dot_flag:数码管的点的亮灭*/
void hd1650_show_each(unsigned char data, unsigned char pos,unsigned char dot_flag)
{
unsigned char tmpData;
//tmpData = asc2code(data);
switch(pos)
{
case :
hd1650_sendcmd(CMD_DIG0(tmpData));
break;
case :
if(dot_flag)
hd1650_sendcmd(CMD_DIG1(tmpData|0x80));
else
//hd1650_sendcmd(CMD_DIG1(tmpData&0x7f));
hd1650_sendcmd(CMD_DIG1(data));
break;
case :
hd1650_sendcmd(CMD_DIG2(tmpData));
break;
case :
hd1650_sendcmd(CMD_DIG3(tmpData));
break;
}
} unsigned char hd1650_getkey(unsigned char *key)
{
unsigned char tmp = ; tmp = hd1650_sendcmd( CMD_GETKEY ); if((tmp & 0x40)== )
tmp = 0x2e; if( key )
*key = tmp; return tmp;
} /*****************************local function implemention*********************************/
/*****************************DO NOT MODIFY*********************************/
static void i2c_start(void)
{
CLK_OUT();
SDA_OUT(); SDA_H();
DELAY();
CLK_H();
DELAY_BUILD();
SDA_L();
DELAY();
} static void i2c_stop(void)
{
SDA_OUT();
SDA_L();
DELAY(); CLK_H();
DELAY_BUILD();
SDA_H();
DELAY(); } /* MSB */
static void i2c_send(unsigned char data)
{
unsigned char i = ;
for(; i < ; i++)
{
CLK_L();
DELAY_BUILD();
if( data & 0x80 )
SDA_H();
else
SDA_L();
data <<= ;
DELAY();
CLK_H();
DELAY();
}
} static unsigned char i2c_recv(unsigned char *data)
{
unsigned char i = , tmp=;
SDA_IN();
for(; i < ; i++)
{
CLK_L();
DELAY();
CLK_H();
DELAY_BUILD();
tmp <<= ;
tmp |= GET_SDA(); DELAY();
}
SDA_OUT(); if( data )
*data = tmp;
return tmp;
} static int i2c_get_ack(void)
{
int i = ; CLK_L();
SDA_IN();
DELAY_BUILD(); CLK_H();
DELAY();
while(GET_SDA() && i-- );
CLK_L();
SDA_OUT(); return ;/*!!!Fixme. this should return the right value, but sometimes the ack cannot get */
} static int i2c_get_ack_getkey(void)
{
int i = ; CLK_L();
SDA_IN();
DELAY_BUILD(); CLK_H();
DELAY();
while(!GET_SDA() && i-- );
CLK_L();
SDA_OUT(); return ;/*!!!Fixme. this should return the right value, but sometimes the ack cannot get */
} static unsigned char hd1650_sendcmd(unsigned short cmd)
{
unsigned char tmp_data = cmd>>; i2c_start();
i2c_send(tmp_data);
if( != i2c_get_ack() )
{
/* printk some error
* hd1650 didnot send the ack
*/
} if( cmd == CMD_GETKEY )
{
i2c_recv(&tmp_data);
if( != i2c_get_ack_getkey())
{
/* printk some error
* hd1650 didnot send the ack
*/
}
}else{
tmp_data = cmd&0x0ff;
i2c_send(tmp_data);
if( != i2c_get_ack())
{
/* printk some error
* hd1650 didnot send the ack
*/
}
} i2c_stop(); return tmp_data;/* just valid for the CMD_GETKEY */
} /*******END OF THE FILE *********/ static int hd1650_ctrl_drv_open(struct node *node, struct file *file )
{
return ;
} static int hd1650_ctrl_drv_release(struct node *node, struct file *file )
{
return ;
} static long hd1650_ctrl_drv_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned char key = ; int ret = ; switch (cmd) {
case GET_KEY:
hd1650_getkey(&key);
ret = put_user(key,(int *)arg);
break;
default:
return -EINVAL; } return ;
} static struct file_operations hd1650_ctl_drv_fileops = {
.owner = THIS_MODULE,
.open = hd1650_ctrl_drv_open,
.unlocked_ioctl = hd1650_ctrl_drv_unlocked_ioctl,
.release = hd1650_ctrl_drv_release
}; static struct miscdevice hd1650_dev = {
MISC_DYNAMIC_MINOR,
"hd1650_dev",
&hd1650_ctl_drv_fileops,
};
int gpio_ctrl_drv_module_init(void)
{
int ret = ; ret = misc_register(&hd1650_dev);
if(ret != )
{
ret = -EFAULT;
return ret;
}
hd1650_init();
hd1650_show_each(0x40 ,,);
printk("hd1650_drv_init ok\n");
return ;
} void gpio_ctrl_drv_module_exit(void)
{ misc_deregister(&hd1650_dev);
printk("gpio_drv_exit ok\n");
} module_init(gpio_ctrl_drv_module_init);
module_exit(gpio_ctrl_drv_module_exit);
MODULE_LICENSE("GPL");

gpio模拟i2c驱动的更多相关文章

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

    目录:一. 说明 二. 驱动程序说明及问题 三. 案例一       四. 案例二 一. 说明 mini210开发板上带了at24c08, 看了linux内核自带的at24.c的驱动程序,编译下载到看 ...

  2. LPC4370使用学习:GPIO的引脚功能使用,和12864OLED模拟I2C驱动

    一: 手中有块LPC4370的开发板,因为便宜,所以引脚引出的不多,而且只有基本的底板资源驱动代码和例程. 看着手册和例程看了老半天,写程序写了半天,结果GPIO老是驱动不起来,因为引脚配置寄存器中有 ...

  3. STM32F207 两路ADC连续转换及GPIO模拟I2C给MT9V024初始化参数

    1.为了更好的方便调试,串口必须要有的,主要打印一些信息,当前时钟.转换后的电压值和I2C读出的数据. 2.通过GPIO 模拟I2C对镁光的MT9V024进行参数初始化.之前用我以前公司SP0A19芯 ...

  4. openwrt 模拟i2c驱动(一)

    一:加载i2c driver kmod-i2c-core................................................ I2C support kmod-i2c-al ...

  5. 【转载】GPIO模拟i2c通信

    I2C总线的通信过程(见图4-8)主要包含三个主要阶段:起始阶段.数据传输阶段和终止阶段. 1. 起始阶段 在I2C总线不工作的情况下,SDA(数据线)和SCL(时钟线)上的信号均为高电平.如果此时主 ...

  6. linux SPI驱动——gpio模拟spi驱动(三)

    一:首先在我的平台注册platform_device,保证能让spi-gpio.c能执行到probe函数. 1: struct spi_gpio_platform_data { 2: unsigned ...

  7. gpio模拟I2C,驱动pcf8574T

    一.pcf8574T介绍 查看pcf8574T的数据手册, A表示读或写,当A为1的时候表示读,当A为0的时候表示写.现把地址控制线,即A2.A1.A0全部接地,可以得到读控制指令为0x41,写控制指 ...

  8. I2C总线以及GPIO模拟I2C

    ·I2C总线的一些特征: 1. 只要求两条总线,一条串行数据线(SDA),一条串行时钟线(SCL) 2. 两个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机系统软件设定的地址:主机可 ...

  9. am335x gpio 模拟 spi 驱动添加

    kernel 内 make menuconfig // make menuconfig Device Drivers ---> [*] SPI support ---> <*> ...

随机推荐

  1. BUUCTF-web ZJCTF,不过如此

    很明显要利用伪协议读next.php base64解码后查看源码 <?php $id = $_GET['id']; $_SESSION['id'] = $id; function complex ...

  2. python基础--迭代器、生成器

    (1)迭代器 可迭代对象和迭代器的解释如下: ''' 什么是对象?Python中一切皆对象,之前我们讲过的一个变量,一个列表,一个字符串,文件句柄,函数名等等都可称作一个对象,其实一个对象就是一个实例 ...

  3. three.js 自制骨骼动画(一)

    上一篇郭先生解析了一下官方的骨骼动画案例,这篇郭先生就要做一个稍微复杂一点的骨骼动画了,就拿一个小人下手吧.在线案例请点击博客原文.话不多说先上大图 骨骼动画在GUI上面都有体现.制作骨骼动画的步骤在 ...

  4. Dynamics 2016 启用Bing Maps

    http://www.krpano360.com/图文详解申请必应地图api密钥 https://crmbook.powerobjects.com/system-administration/inte ...

  5. x86架构: 硬件启动过程分析(附引导启动代码)

    用户按下开机键,几秒的时间,都经历了啥? 1.cpu各个寄存器赋初始值,cs.base=0xffff0000, eip=0xfff0,其他寄存器都是0,这时cs:ip得到的物理地址:0xfffffff ...

  6. 3行!仅3行代码就能抓取B站(弹幕、评论、用户)数据

    今天介绍一个获取B站数据的Python扩展库-bilibili_api 可以获取的数据包括: video-视频模块 user-用户模块 dynamic-动态模块 这次用“Running Man”十周年 ...

  7. dos下mybatis自动生成代码

    今天来介绍下怎么用mybatis-gennerator插件自动生成mybatis所需要的dao.bean.mapper xml文件,这样我们可以节省一部分精力,把精力放在业务逻辑上. 之前看过很多文章 ...

  8. 029_go语言中的非阻塞通道

    代码演示 package main import "fmt" func main() { messages := make(chan string) signals := make ...

  9. Android Studio--APK打包

    首先在app的build.gradle里面加一下代码 lintOptions { checkReleaseBuilds false abortOnError false } 在上方Build里面找到G ...

  10. NIO(一):Buffer缓冲区

    一.NIO与IO: IO:  一般泛指进行input/output操作(读写操作),Java IO其核心是字符流(inputstream/outputstream)和字节流(reader/writer ...