前段时间做项目,需要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. python可变与不可变数据类型+深浅拷贝

    转自:https://www.cnblogs.com/miaomiaokaixin/p/11497813.html 一:学习内容 python3中六种数据类型 python赋值 python浅拷贝 p ...

  2. python xpath的基本用法

    XPath是一种在XML文档中查找信息的语言,使用路径表达式在XML文档中进行导航.学习XPath需要对XML和HTML有基本的了解. 在XPath中,有七种类型的节点:文档(根)节点.元素.属性.文 ...

  3. Linux内存参数

    用free -m查看的结果:# free -m         total    used    free     shared buffers     cachedMem:           50 ...

  4. 编写优美Android注释的常用语法

    编写优美Android注释的常用语法   短期目标是定期能出一篇简文,希望自己能坚持下去~~~~( ̄_, ̄ )   附上Android君 今天要分享的是关于Android注释系统的一些强大功能!! 实 ...

  5. Ubuntu Linux markdown编辑工具 typora 安装

    Typora简介 Typora是一款轻便简洁的Markdown编辑器,支持即时渲染技术,这也是与其他Markdown编辑器最显著的区别.即时渲染使得你写Markdown就想是写Word文档一样流畅自如 ...

  6. Hyper-V设置固定IP

    win+x以管理员启动PowerShell 创建虚拟交换机,等同于在Hyper-V管理器界面中新建虚拟网络交换机 New-VMSwitch -SwitchName "NAT-VM" ...

  7. PHP utf8_decode() 函数

    定义和用法 utf8_decode() 函数把 UTF-8 字符串解码为 ISO-8859-1.高佣联盟 www.cgewang.com 该函数把通过 utf8_encode() 函数编码的 ISO- ...

  8. PDOStatement::closeCursor

    PDOStatement::closeCursor — 关闭游标,使语句能再次被执行.(PHP 5 >= 5.1.0, PECL pdo >= 0.9.0) 说明 语法 bool PDOS ...

  9. Hibernate Validator校验参数全攻略

    1. 前言 数据字段一般都要遵循业务要求和数据库设计,所以后端的参数校验是必须的,应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的. 2. 数据校验的痛点 为了保证数据语义的正确,我们 ...

  10. ios迅雷上架成功的秘密 背后的“苹果TF签名”

    距离ios迅雷从App Store下架已经过去很久了,小微经常看到知乎里有很多迅雷用户到处寻找可以下载应用的渠道.近期迅雷被爆“好消息”iOS 迅雷(官方版)正式上架 App Store,此消息一出可 ...