因为项目需要,用的板子是比较冷门的德州仪器am1808芯片,这款芯片没有AD/DA,我就自己从某宝买了pcf8591数模转换模块,本想直接接入I2c总线,因为linux自带i2c驱动,无奈,他是7位的I2c,最大地址限定在0x77,而我的AD模块的地址是0x90,所以接入总线失败;我又想了一种方法,自己写一个单片机版本的I2c专门给pcf8591用,但是奇怪的事情发生了,数据不管怎么读都是低电平,弄了好多天,还是不行,我附上代码,望大侠帮忙下,因为比较急。谢谢了。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
//#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/timer.h>
#include "am1808_gpio.h"
/* 相关引脚定义,方便以后移植 */
#define SDA I2C0_SDA
#define SCL I2C0_SCL
//#define SDA EMA_A_16_EXP
//#define SCL EMA_A_15_EXP
#define PCF8591_ADDR 0x90
// 主次设备号(动态分配)
int pcf8591_minor = 0;
int pcf8591_nr_devs = 1;
//应答标志
unsigned char ack;
/* 函数声明 */
static int pcf8591_open(struct inode *inode, struct file *filp);
static ssize_t pcf8591_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos);
//模拟I2C总线函数
static void i2c_start(void);
static void i2c_stop(void);
static void sendbyte(unsigned char c);
static unsigned char rcvbyte(void);
static void i2c_ack(unsigned char a);
//ADC转换函数
unsigned char ISendByte(unsigned char sla,unsigned char c);
unsigned char IRcvByte(unsigned char sla);
static void i2c_start(void)
{
gpio_set_value(SDA, 1);
udelay(1);
gpio_set_value(SCL, 1);
udelay(5);
gpio_set_value(SDA, 0);
udelay(5);
gpio_set_value(SCL, 0);
udelay(2);
}
static void i2c_stop(void)
{
gpio_set_value(SDA, 0);
udelay(1);
gpio_set_value(SCL, 1);
udelay(5);
gpio_set_value(SDA, 1);
udelay(4);
}
static void sendbyte(unsigned char c)
{
unsigned char BitCnt;
for(BitCnt = 0;BitCnt<8;BitCnt++)
{
if((c<<BitCnt)&0x80)
gpio_set_value(SDA, 1);
else
gpio_set_value(SDA, 0);
udelay(1);
gpio_set_value(SCL, 1);
udelay(5);
gpio_set_value(SCL, 0);
}
udelay(2);
gpio_direction_input(SDA);
udelay(2);
gpio_set_value(SCL, 1);
udelay(3);
if(gpio_get_value(SDA) != 0)
ack = 0;
else
ack = 1;
gpio_set_value(SCL, 0);
gpio_direction_output(SDA, 1);//钳住总线
udelay(2);
}
static unsigned char rcvbyte(void)
{
unsigned char retc;
unsigned char BitCnt;
retc = 0;
gpio_direction_input(SDA);
gpio_set_value(SDA, 1);
for(BitCnt=0;BitCnt<8;BitCnt++)
{
udelay(1);
gpio_set_value(SCL, 0);
udelay(5);
gpio_set_value(SCL, 1);
udelay(2);
retc = retc<<1;
if(gpio_get_value(SDA) != 0)
{
printk(KERN_WARNING "SDA=1\n");
retc += 1;
}
else
printk(KERN_WARNING "SDA=0\n");
udelay(2);
}
gpio_set_value(SCL, 0);
gpio_direction_output(SDA, 1);
udelay(2);
return retc;
}
static void i2c_ack(unsigned char a)
{
if(a != 1)
gpio_set_value(SDA, 0);
else
gpio_set_value(SDA, 1);
udelay(3);
gpio_set_value(SCL, 1);
udelay(5);
gpio_set_value(SCL, 0);
udelay(2);
}
unsigned char ISendByte(unsigned char sla,unsigned char c)
{
i2c_start();
sendbyte(sla);
if(ack == 0)
return 0;
sendbyte(c);
if(ack == 0)
return 0;
i2c_stop();
return 1;
}
unsigned char IRcvByte(unsigned char sla)
{
unsigned char c;
i2c_start();
sendbyte(sla+1);
if(ack == 0)
return 0;
c = rcvbyte();
i2c_ack(1);
i2c_stop();
return c;
}
/*************************************************************************
*****************************
** 函数名称: pcf8591_open()
** 函数功能: 打开设备,初始化驱动
** 入口参数: inode:设备文件信息; filp: 被打开的文件的信息
** 出口参数: 成功时返回0,失败返回-1
** 备 注:
**************************************************************************
****************************/
static int pcf8591_open(struct inode *inode, struct file *filp)