具体的驱动程序如下
#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; }