将HMC5883移植到S5PV210上

      HMC5883是一个三轴的指南针模块,其工作原理请自行百度。这里采用模拟IIC协议实现与HMC5883的通信。

具体的驱动程序如下

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-adc.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/gpio.h>

#define DEVICE_NAME "hmc5883"
#define SlaveAddress 0x3c //定义器件在IIC总线中的从地址

#define SDA S5PV210_GPH3(3) //SDA所在引脚定义
#define SCL S5PV210_GPH3(2) //SCL所在引脚定义
#define ONE 1 //高电平
#define ZERO 0 //低电平
#define UDELAY {udelay(5);}
#define MDELAY {mdelay(5);}

unsigned char buf[6]; //save hmc5883 data buf

//起始信号
void hmc5883_start(void) //SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
{
    gpio_set_value(SDA, 1); //拉高数据线
    gpio_set_value(SCL, 1); //拉高时钟线
    UDELAY; //延时
    gpio_set_value(SDA, 0); //产生下降沿
    UDELAY; //延时
    gpio_set_value(SCL, 0); //拉低时钟线
}

//停止信号
void hmc5883_stop (void) //SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。
{

    gpio_set_value(SDA, 0); //拉低数据线
    gpio_set_value(SCL, 1); //拉高时钟线
    UDELAY; //延时
    gpio_set_value(SDA, 1); //产生上升沿
    UDELAY; //延时
}

//发送应答信号 入口参数:ack (0x0:ACK 0x01:NAK)
void hmc5883_sendack(unsigned char ack)
{

    if(ack) //写应答信号
    gpio_set_value(SDA, 1);
    else
    gpio_set_value(SDA, 0);
    gpio_set_value(SCL, 1); //拉高时钟线
    UDELAY; //延时
    gpio_set_value(SCL, 0); //拉低时钟线
    UDELAY; //延时
}

//接收应答信号
unsigned char hmc5883_recvack(void)
{
    unsigned char cy;
    gpio_set_value(SCL, 1); //拉高时钟线
    s3c_gpio_cfgpin(SDA,S3C_GPIO_INPUT);
    UDELAY ; //延时
    cy=s3c_gpio_cfgpin(SDA,S3C_GPIO_INPUT);
    gpio_set_value(SCL, 0); //拉低时钟线
    UDELAY; //延时
    s3c_gpio_cfgpin(SDA,S3C_GPIO_OUTPUT);
    UDELAY;
    return cy;
}

//向IIC总线发送一个字节数据
void hmc5883_sendbyte(unsigned char dat)
{
    unsigned char i;
    unsigned char cy[8];
    unsigned char data;
    for (i=0; i<8; i++) //获取字节的每一位
    {
    data=dat&0x80;
    if(data)
    cy[i]=ONE;
    else
    cy[i]=ZERO;
    dat<<=1;
    }
    for (i=0; i<8; i++) //8位计数器
    {
    gpio_set_value(SDA, cy[i]); //送数据口
    gpio_set_value(SCL, 1); //拉高时钟线
    UDELAY; //延时
    gpio_set_value(SCL, 0); //拉低时钟线
    UDELAY; //延时
    }
    hmc5883_recvack();
}

//从IIC总线接收一个字节数据
unsigned char hmc5883_recvbyte(void)
{
    unsigned char i;
    unsigned char dat = 0;
    gpio_set_value(SDA,1); //准备读取数据
    s3c_gpio_cfgpin(SDA, S3C_GPIO_INPUT);
    UDELAY;
    for (i=0; i<8; i++) //8位计数器
    {
    dat <<= 1;
    gpio_set_value(SCL, 1); //拉高时钟线
    UDELAY ; //延时
    dat |= gpio_get_value(SDA); //读数据
    gpio_set_value(SCL, 0); //拉低时钟线
    UDELAY; //延时
    }
    s3c_gpio_cfgpin(SDA,S3C_GPIO_OUTPUT);
    UDELAY;
    printk("%d\n",dat);
    return dat;
}

void single_write_hmc5883(unsigned char reg_address,unsigned char reg_data)
{
    hmc5883_start();
    hmc5883_sendbyte(SlaveAddress);
    hmc5883_sendbyte(reg_address);
    hmc5883_sendbyte(reg_data);
    hmc5883_stop();
}

#if 0
unsigned char single_read_hmc5883(unsigned char reg_address)
{
    unsigned char reg_data;
    hmc5883_start();
    hmc5883_sendbyte(SlaveAddress);
    hmc5883_sendbyte(reg_address);
    hmc5883_start();
    hmc5883_sendbyte(SlaveAddress+1);
    reg_data=hmc5883_recvbyte();
    hmc5883_sendack(0x1);
    hmc5883_stop();
    return reg_data;
}
#endif

void multiple_read_hmc5883(void)
{
    unsigned char i;
    hmc5883_start(); //起始信号
    hmc5883_sendbyte(SlaveAddress); //发送设备地址+写信号
    hmc5883_sendbyte(0x03); //发送存储单元地址
    hmc5883_start(); //起始信号
    hmc5883_sendbyte(SlaveAddress+1); //发送设备地址+读信号
    for(i=0;i<6;i++)
    {
    buf[i]=hmc5883_recvbyte(); //BUF[0]存储
    if(i==5)
    hmc5883_sendack(0x01); //最后一个数据需要回NOACK
    else
    hmc5883_sendack(0x0); //回应ACK
    }
    hmc5883_stop(); //停止信号
    MDELAY; //延时
}


void init_hmc5883(void)
{
    single_write_hmc5883(0x02,0x00);
}


static int hmc5883_open(struct inode *inode, struct file *file)
{
    printk("open hmc5883 in kernel\n");
    init_hmc5883();
    return 0;
}


static int hmc5883_read (struct file *filp, char __user *buffer, size_t length, loff_t*ops)
{
    int ret;
    multiple_read_hmc5883();
    ret=copy_to_user(buffer,buf,sizeof(buf));
    if(ret<0)
    printk("hmc5883 copy to user err\n");
    return 0;
}


static int hmc5883_release(struct inode *inode, struct file *file)
{
    printk("hmc5883_release in kernel\n");
    return 0;
}

static struct file_operations hmc5883_dev_fops={
    .owner = THIS_MODULE,
    .open = hmc5883_open,
    .read = hmc5883_read,
    .release = hmc5883_release,
};

static struct miscdevice hmc5883_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &hmc5883_dev_fops,
};

static int __init hmc5883_dev_init(void) {
    int ret;
    ret = gpio_request(SDA, "hmc5883_sda");
    if (ret) {
    printk("%s: request GPIO %d for hmc5883 failed, ret = %d\n", DEVICE_NAME,SDA, ret);
    return ret;
    }
    ret = gpio_request(SCL, "hmc5883_scl");
    if (ret){
    printk("%s: request GPIO %d for hmc5883 failed, ret = %d\n", DEVICE_NAME,SCL, ret);
    return ret;
    }
    s3c_gpio_cfgpin(SDA, S3C_GPIO_OUTPUT);
    s3c_gpio_cfgpin(SCL, S3C_GPIO_OUTPUT);
    ret = misc_register(&hmc5883_dev);
    printk(DEVICE_NAME"\tinitialized\n");
    return ret;
}

static void __exit hmc5883_dev_exit(void)
{
    gpio_free(SDA);
    gpio_free(SCL);
    misc_deregister(&hmc5883_dev);
}

module_init(hmc5883_dev_init);
module_exit(hmc5883_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("www");


具体的App程序如下

#include <stdio.h>
#include <strings.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <math.h>

int hmcfd;  //bmp085文件描述符

void convertion(char *buf)
{
        double angle;
        short x,y,z;
	x=buf[0]<<8 | buf[1]; //Combine MSB and LSB of X Data output register
	z=buf[2]<<8 | buf[3]; //Combine MSB and LSB of Z Data output register
	y=buf[4]<<8 | buf[5]; //Combine MSB and LSB of Y Data output register
	printf("x=%hd\n",x);
	printf("y=%hd\n",y);
	printf("z=%hd\n",z);
	angle=atan2((double)y,(double)x)* (180 / 3.14159265) + 180; // angle in degrees
	printf("the angle is %lf\n",angle);
}
int main(int argc,char **argv)
{
	hmcfd=open("/dev/hmc5883",O_RDWR);
	if(hmcfd<0)
	{
	printf("open hmc5883 err!\n");
	printf("please cheek!\n");
	exit(-1);
	}
	printf("open hmc5883 ok!\n");
	int ret;
	char buf[5];
	while(1)
	{
	bzero(buf,sizeof(buf));
	ret=read(hmcfd,buf,sizeof(buf));
	if(ret<0)
	printf("read from hmc5883 err!\n");
	convertion(buf);
	sleep(1);
	}
	close(hmcfd);
	return 0;
}

这样,HMC5883的移植工作算是完成了。 

你可能感兴趣的:(s5pv210,HMC5883)