我编写DS18b20程序,想显示温度在三个LED灯上,但LED一直数字不变,下面是程序,开发板TX-1C晶振 11.0592M
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我编写DS18b20程序,想显示温度在三个LED灯上,但LED一直数字不变,下面是程序,开发板TX-1C晶振 11.0592M相关的知识,希望对你有一定的参考价值。
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
uint temp;
uchar num4,num5,num6;
sbit duan=P2^6;
sbit wein=P2^7;
sbit D1=P0^7;
sbit DS=P2^2;
uchar code table[]=
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71;
void delay(uint aa)//延时
int x,y;
for(x=0;x<aa;x++)
for(y=0;y<200;y++);
void startck()//开启串口
TMOD=0x20;
PCON=0X00;
SCON=0X50;
TH1=0xfd;
TL1=0xfd;
TR1=1;
void startds()//启动DS18b20
uint i;
DS=0;
for(i=103;i>0;i--);//延时
DS=1;
for(i=4;i>0;i--);//延时
bit readbit(void)//读取一个bit
uchar a;
bit bit1;//用来返回读到的一个字bit
a=0;
DS=0;
a++;
DS=1;
a++;a++;
bit1=DS;
for(a=0;a<8;a++);
return(bit1);
uchar readbyte(void)//读取一个字节
uchar date,a,b;
b=0;date=0;
while(b<8)
a=readbit();
date=(a<<7)|(date>>1);//将readbit()的返回值付给date,然后date向后移一位 重复8次刚好 得到一个字节的数据
b++;
return(date);
void writeor(uchar order)//写入命令
uint b;
uchar a;
bit bit2;
b=0;
for(a=0;a<8;a++)
bit2=order&0x01;
if(bit2)//写入1
DS=0;
b++,b++;
DS=1;
for(b=0;b<8;b++);
else//0
DS=0;
for(b=0;b<8;b++);
DS=1;
b++;b++;
void changetemp()//温度转变函数
startds();
delay(1);
writeor(0xcc);// 跳过读序号列号的操作
writeor(0x44);// 启动温度转换
uint gettemp()//获取温度
float tt;
uchar geta,getb;
startds();
delay(1);
writeor(0xcc);
writeor(0xbe);//读取温度命令
geta=readbyte();//读取两个字节
getb=readbyte();
temp=getb;
temp<<=8;//左移8位
temp=temp|geta;
tt=temp*0.0625;//将temp中的数转化成实际的温度值
temp=tt*10+0.5;//,变大十倍且 四舍五入
return(temp);
void display(uint temp)//显示函数 这里wein是位选 duan是段选
num4=temp/100;//将temp的百十个位分别取出 分别是num4、num5、num6
num5=temp%100/10;
num6=temp%10;
wein=1;
P0=0x37;//wein打开后 是低电平亮 第四个LED灯亮
wein=0;
P0=0xff;
duan=1;
P0=table[num4];
duan=0;
P0=0xff;
delay(3);
wein=1;
P0=0x2f;
wein=0;
P0=0xff;
duan=1;
P0=table[num5];
D1=1;//家上小数点 P0^7
duan=0;
P0=0xff;
delay(3);
wein=1;
P0=0x1f;
wein=0;
P0=0xff;
duan=1;
P0=table[num6];
duan=0;
P0=0xff;
delay(3);
void main()
uchar a;
startck();
while(1)
changetemp();
for(a=10;a>0;a--)
display(gettemp());//显示十次
数字一直显示8.5.9
#include<intrins.h>
#include <math.H> //要用到取绝对值函数abs()
#define uchar unsigned char
#define uint unsigned int
sbit ds=P2^1; //sbit ds=P3^2;//DS18B20
sbit duan=P2^6;
sbit wei=P2^7;
uchar i;
unsigned char code table[]=0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x00,0x40; //0x00是用在显示函数中0x40显示“-”(负号)
//****************************************************************
void delay(uchar i)
uint j;
while(i--)
for(j = 0; j < 125; j++);
//****************************************************************
//延时函数, 对于11.0592MHz时钟, 例i=10,则大概延时10ms.
void dsInit()
//对于11.0592MHz时钟, unsigned int型的i, 作一个i++操作的时间大于8us
unsigned int i;
ds = 0;
i = 100; //拉低约800us, 符合协议要求的480us以上
while(i>0) i--;
ds = 1; //产生一个上升沿, 进入等待应答状态
i = 4;
while(i>0) i--;
void dsWait()
unsigned int i;
while(ds); //等待应答信号
while(~ds); //检测到应答脉冲
i = 4;
while(i > 0) i--;
//向DS18B20读取一位数据
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
//之后DS18B20则会输出持续一段时间的一位数据
bit readBit()
unsigned int i;
bit b;
ds = 0;
i++; //延时约8us, 符合协议要求至少保持1us
ds = 1;
i++;
i++; //延时约16us, 符合协议要求的至少延时15us以上
b = ds;
i = 8;
while(i>0) i--; //延时约64us, 符合读时隙不低于60us要求
return b;
//读取一字节数据, 通过调用readBit()来实现
unsigned char readByte()
unsigned int i;
unsigned char j, dat;
dat = 0;
for(i=0; i<8; i++)
j = readBit();
//最先读出的是最低位数据
dat = (j << 7) | (dat >> 1);
return dat;
//向DS18B20写入一字节数据
void writeByte(unsigned char dat)
unsigned int i;
unsigned char j;
bit b;
for(j = 0; j < 8; j++)
b = dat & 0x01;
dat >>= 1;
//写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
if(b)
ds = 0;
i++;
i++; //拉低约16us, 符号要求15~60us内
ds = 1;
i = 8; while(i>0) i--; //延时约64us, 符合写时隙不低于60us要求
else //写"0", 将DQ拉低60us~120us
ds = 0;
i = 8; while(i>0) i--; //拉低约64us, 符号要求
ds = 1;
i++;
i++; //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了
//向DS18B20发送温度转换命令
void sendChangeCmd()
dsInit(); //初始化DS18B20, 无论什么命令, 首先都要发起初始化
dsWait(); //等待DS18B20应答
delay(1); //延时1ms, 因为DS18B20会拉低DQ 60~240us作为应答信号
writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
writeByte(0x44); //写入温度转换命令字 Convert T
//向DS18B20发送读取数据命令
void sendReadCmd()
// EA=0;//关闭中断是因为进入显示中断会影响到DS18B20的读写时序
dsInit();
dsWait();
delay(1);
writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
writeByte(0xbe); //写入读取数据令字 Read Scratchpad
// EA=1;
//获取当前温度值
int getTmpValue()
unsigned int tmpvalue;
int value; //存放温度数值
float t;
unsigned char low, high;
// EA=0;
sendReadCmd();
//连续读取两个字节数据
low = readByte();
high = readByte();
//将高低两个字节合成一个整形变量
//计算机中对于负数是利用补码来表示的
//若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的value
tmpvalue = high;
tmpvalue <<= 8;
tmpvalue |= low;
value = tmpvalue;
//使用DS18B20的默认分辨率12位, 精确度为0.0625度, 即读回数据的最低位代表0.0625度
t = value * 0.0625;
//将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三进行4舍5入
//如t=11.0625, 进行计数后, 得到value = 1106, 即11.06 度
//如t=-11.0625, 进行计数后, 得到value = -1106, 即-11.06 度
value = t * 100 + (value > 0 ? 0.5 : -0.5); //大于0加0.5, 小于0减0.5
return value;
// EA=1;
/*
void Init_timer0()
TMOD=0x01;
TH0=th0;
TL0=tl0;
EA=1;
ET0=1;
TR0=1;
*/
void display(int dd)
uchar SH,SZ,SL,GH,GL,i,temp;
uchar dis[8]=10,10,10,10,10,10,10,10; //从【5-8】的数字为10,相应的段码是0x00,即不显示
uint dda;
dda=abs(dd);
SH = dda/ 10000;
SZ = dda % 10000 / 1000;
SL = dda % 1000 / 100;
GH = dda % 100 / 10;
GL = dda % 10;
dis[0]=GL;
dis[1]=GH;
dis[2]=SL;
if((SZ==0)&&(SH==0))
dis[3]=10;
else
dis[3]=SZ;
if (dd<0)
dis[4]=11; //是负温度,显示“-”
else
if(SH==0)
dis[4]=10; //温度高位是0,不显示
else
dis[4]=SH;
temp=0xbf;
for(i=0;i<8;i++)
P0=0xff;
wei=1;
temp=_cror_(temp,1);
P0=temp;
wei=0;
P0=0;
duan=1;
if(i==2)
P0=0x80|table[dis[2]];
else
P0=table[dis[i]];
duan=0;
delay(1);
/*
P0=0xff;
wei=1;
P0=0xdf;
wei=0;
P0=0;
duan=1;
P0=table[GL];
delay(1);
duan=0;
P0=0xff;
wei=1;
P0=0xef;
wei=0;
P0=0;
duan=1;
P0=table[GH];
delay(1);
duan=0;
P0=0xff;
wei=1;
P0=0xf7;
wei=0;
P0=0;
duan=1;
P0=table[SL]|0x80;
delay(1);
duan=0;
P0=0xff;
wei=1;
P0=0xfb;
wei=0;
P0=0;
duan=1;
P0=table[SZ];
delay(1);
duan=0;
P0=0xff;
wei=1;
P0=0xfd;
wei=0;
P0=0;
duan=1;
P0=table[SH];
delay(1);
duan=0;
P0=0xff;
wei=1;
P0=0xff;
wei=0; */
void main()
int tempValue1;
// init();
// Init_timer0();
while(1)
//启动温度转换
sendChangeCmd();
tempValue1 = getTmpValue();
display(tempValue1);
//根据自己的硬件改改端口,我已经成功了
参考资料:自己亲身经历
参考技术A 呀 C我看不懂,我只会点汇编,如果你的温度显示是8.5.9显然是你程序错了,两个小数点,如果程序调试没问题的话,大概有两种情况,一是你的DS18B20接反了,二是坏了,你用万用表检查一下,坏了就换一个 参考技术B 应该是时序不对,18B20对时序要求很严格基于TINY4412的Andorid开发-------简单的LED灯控制
本文转载自:http://www.cnblogs.com/pengdonglin137/p/3857724.html
基于TINY4412的Andorid开发-------简单的LED灯控制
参考资料:
《Andriod系统源代码情景分析》
《嵌入式Linux系统开发完全手册_基于4412_上册》
作者:彭东林
平台介绍:
主机:Win7 32位
虚拟机:VMware10 + ubuntu-12.04.2-desktop-amd64
Android版本: android-4.2.2_r1
Linux内核版本:linux-3.5.0
Bootloader: 友善之臂提供的Superboot4412.bin
目标平台:tiny4412ADK+S700 4GB Flash
目的: 在Tiny4412上运行的Android系统上,通过点击屏幕上的Button来控制Tiny4412的核心板上的四个LED灯的亮灭。一个有八个Button,每个灯的亮灭通过两个灯来控制,点击ON,相应的LED亮;点击OFF,相应的LED灯灭。
下面分几步完成:
1、编写驱动程序
2、测试驱动程序
3、编写HAL代码
4、编写framework代码
5、编写JNI代码
6、编写App
下面开始:
一、编写驱动程序
分析tiny4412的原理图,看一下LED灯的位置:
可以知道,LED是低电平亮,高电平灭。
看一下,接到了Exynos4412的哪些引脚上了:
可以看到:
LED1 --------- GPM4_0
LED2 --------- GPM4_1
LED3 --------- GPM4_2
LED4 --------- GPM4_3
看一下Exynos4412的芯片手册,看一下GPM4的相关寄存器:
图中第二列表示的相对于基地址的偏移量,这里基地址是:0x11000000.
在芯片手册的Page288 ~ Page291对这些寄存器有更详细的介绍。
以GPM4_0引脚为例:
为了控制灯,[3:0]应设置为0x01,即输出模式
向GPM4DAT的第0位写0,GPM4_0引脚输出低电平,LED1亮;
向GPM4DAT的第0位写1,GPM4_0引脚输出高电平,LED1灭;
接下来,开始写驱动程序,用友善之臂自带的Linux3.5.0内核
1: cd linux-3.5/
2: cd drivers/
3: mkdir android_led
4: cd android_led/
在android_led/下创建led_demo.c和led_demo.h文件:
touch led_demo.c led_demo.h
再在其中创建Makefile和Kconfig文件
touch Makefile Kconfig
- 修改Kconfig:
1: config LED_DEMO
2: tristate "Android Led Demo"
3: default n
4: help
5: This is the led demo for Android system.
- 修改Makefile:
obj-$(CONFIG_LED_DEMO) += led_demo.o
- 修改drivers/Kconfig,添加 source “drivers/android_led/Kconfig”
1: menu "Device Drivers"
2:
3: source "drivers/android_led/Kconfig"
4:
5: ......
6:
7: endmenu
- 修改drivers/Makefile:
1: ......
2:
3: obj-$(CONFIG_LED_DEMO) += android_led/
- 在内核顶层目录下执行make menuconfig,进入Device Drivers,将 Android Led Demo选择为*,然后保存配置退出。
注:执行上面这些操作之前,确保已经按照友善之臂的手册,成功编译了Android上用的Linux内核,并且在arch/arm/boot下生成了zImage等文件。
在前期开发的时候,时不时要编译,可以将drivers/android_led/Makefile修改为:
1: #obj-$(CONFIG_LED_DEMO) += led_demo.o
2: obj-m += led_demo.o
编译的时候,可以使用:
make M=drivers/android_led modules
目的是提高编译速度,最后再将Makfile改回原样。临时测试,可以在Wind7的命令行下,使用adb push将led_demo.ko上传到/data/local下,然后用adb shell登陆板子,进行测试。
- 修改led_demo.h和led_demo.c
led_demo.h:
1: #ifndef __LED_DEMO_H__
2: #define __LED_DEMO_H__
3:
4: #include <linux/cdev.h>
5:
6: #define LED_ON _IOW(\'L\', 0, int)
7: #define LED_OFF _IOW(\'L\', 1, int)
8:
9: #define LED_DEMO_DEVICE_NODE_NAME "led_demo"
10: #define LED_DEMO_DEVICE_CLASS_NAME "led_demo"
11: #define LED_DEMO_DEVICE_FILE_NAME "led_demo"
12:
13: #define EXYNOS4412_GPM4CON 0x110002E0
14: #define EXYNOS4412_GPM4DAT 0x110002E4
15:
16:
17: struct led_demo_dev
18: {
19: struct cdev dev;
20: };
21:
22: #endif
led_demo.c:
1: #include <linux/kernel.h>
2: #include <linux/module.h>
3: #include <linux/fs.h>
4: #include <linux/slab.h>
5: #include <linux/device.h>
6:
7: #include <asm/io.h>
8: #include <asm/uaccess.h>
9:
10:
11: #include "led_demo.h"
12:
13:
14: MODULE_LICENSE("GPL");
15:
16:
17: static int led_demo_major;
18: static int led_demo_minor;
19: static int number_of_dev = 1;
20:
21: static struct led_demo_dev *led_dev = NULL;
22:
23: static unsigned int *GPM4CON = NULL;
24: static unsigned int *GPM4DAT = NULL;
25:
26: static struct class *led_demo_class = NULL;
27:
28:
29: static int led_open (struct inode *node, struct file *fops)
30: {
31: struct led_demo_dev *dev;
32:
33: dev = container_of(node->i_cdev, struct led_demo_dev, dev);
34:
35: fops->private_data = dev;
36:
37: return 0;
38: }
39: static int led_close (struct inode *node, struct file *fops)
40: {
41: return 0;
42: }
43:
44: static long led_ioctl (struct file *fops, unsigned int cmd, unsigned long data)
45: {
46: //struct led_demo_dev * led_dev = (struct led_demo_dev *)fops->private_data;
47:
48: if((data < 1) || (data > 4))
49: {
50: printk(KERN_ALERT"parameter is no valid.\\n");
51: return -EINVAL;
52: }
53:
54: switch (cmd)
55: {
56: case LED_OFF:
57: writel(readl(GPM4DAT) | (0x1<<(data-1)), GPM4DAT);
58: break;
59: case LED_ON:
60: writel(readl(GPM4DAT) & ~(0x1<<(data-1)), GPM4DAT);
61: break;
62: default:
63: return -EINVAL;
64: break;
65: }
66:
67:
68: return 0;
69: }
70:
71: struct file_operations led_fops =
72: {
73: .owner = THIS_MODULE,
74: .open = led_open,
75: .unlocked_ioctl = led_ioctl,
76: .compat_ioctl = led_ioctl,
77: .release = led_close,
78: };
79:
80: static int __led_setup_dev(struct led_demo_dev * dev)
81: {
82: int err = -1;
83:
84: dev_t devno = MKDEV(led_demo_major, led_demo_minor);
85:
86: memset(dev, 0, sizeof(struct led_demo_dev));
87:
88: cdev_init(&(dev->dev), &led_fops);
89:
90: dev->dev.owner = THIS_MODULE;
91:
92: err = cdev_add(&(dev->dev), devno, number_of_dev);
93: if(err < 0)
94: {
95: return err;
96: }
97:
98: return 0;
99: }
100:
101: static int led_demo_init(void)
102: {
103: int err = -1;
104: dev_t dev;
105: struct device *temp = NULL;
106:
107: printk(KERN_ALERT"Initializing led demo device.\\n");
108:
109: err = alloc_chrdev_region(&dev, 0, number_of_dev, LED_DEMO_DEVICE_NODE_NAME);
110: if(err < 0)
111: {
112: printk(KERN_ALERT"fail to alloc char dev region.\\n");
113: goto fail;
114: }
115:
116: led_demo_major = MAJOR(dev);
117: led_demo_minor = MINOR(dev);
118:
119: led_dev = kmalloc(sizeof(struct led_demo_dev), GFP_KERNEL);
120: if(!led_dev)
121: {
122: err = -ENOMEM;
123: printk(KERN_ALERT"Failed to alloc led device.\\n");
124: goto unregister;
125: }
126:
127: err = __led_setup_dev(led_dev);
128: if (err < 0)
129: {
130: printk(KERN_ALERT"Failed to setup led device.\\n");
131: goto clean_up;
132: }
133:
134: GPM4CON = (unsigned int *)ioremap(EXYNOS4412_GPM4CON, 4);
135: if(!GPM4CON)
136: {
137: err = -ENOMEM;
138: goto destroy_cdev;
139: }
140:
141: GPM4DAT = (unsigned int *)ioremap(EXYNOS4412_GPM4DAT, 4);
142: if(!GPM4DAT)
143: {
144: err = -ENOMEM;
145: goto unmap1;
146: }
147:
148: writel((readl(GPM4CON) & ~0xffff) | 0x1111, GPM4CON);
149: writel(readl(GPM4DAT)| 0xf, GPM4DAT);
150:
151: led_demo_class = class_create(THIS_MODULE, LED_DEMO_DEVICE_CLASS_NAME);
152: if(IS_ERR(led_demo_class))
153: {
154: err = PTR_ERR(led_demo_class);
155: printk(KERN_ALERT"Failed to create led demo class.\\n");
156: goto unmap2;
157: }
158:
159: temp = device_create(led_demo_class, NULL, dev, NULL, "%s", LED_DEMO_DEVICE_FILE_NAME);
160: if(IS_ERR(temp))
161: {
162: err = PTR_ERR(temp);
163: printk(KERN_ALERT"Failed to create led demo device.\\n");
164: goto destroy_class;
165: }
166:
167: dev_set_drvdata(temp, (void *)led_dev);
168:
169: printk(KERN_ALERT"Succeed to initialize led demo device.\\n");
170:
171: return 0;
172:
173: destroy_class:
174: class_destroy(led_demo_class);
175:
176: unmap2:
177: iounmap(GPM4DAT);
178:
179: unmap1:
180: iounmap(GPM4CON);
181:
182: destroy_cdev:
183: cdev_del(&(led_dev->dev));
184:
185: clean_up:
186: kfree(led_dev);
187:
188: unregister:
189: unregister_chrdev_region(MKDEV(led_demo_major, led_demo_minor), number_of_dev);
190:
191: fail:
192:
193: return err;
194: }
195:
196: static void led_demo_exit(void)
197: {
198: if(led_demo_class)
199: {
200: device_destroy(led_demo_class, MKDEV(led_demo_major, led_demo_minor));
201: class_destroy(led_demo_class);
202: }
203:
204: iounmap(GPM4DAT);
205: iounmap(GPM4CON);
206:
207: if(led_dev)
208: {
209: cdev_del(&(led_dev->dev));
210: kfree(led_dev);
211: }
212:
213: unregister_chrdev_region(MKDEV(led_demo_major, led_demo_minor), number_of_dev);
214: }
215:
216:
217:
218: module_init(led_demo_init);
219: module_exit(led_demo_exit);
220:
编写完成后,在内核源码的顶层目录执行make zImage –jN,然后就会在arch/arm/boot/生成zImage文件,利用友善之臂提供的Minitools将zImage烧写到板子上。具体步骤,参考友善之臂提供的PDF文档:《Tiny4412用户手册》
二、编写代码测试驱动程序
在android-4.2.2_r1源码顶层目录下
1: external/led_demo/
2: ├── Android.mk
3: ├── led_demo.c
4: └── led_demo.h
即,在external/下创建led_demo目录,并在其中创建Android.mk、led_demo.c以及led_demo.h文件.
Android.mk:
1: LOCAL_PATH:= $(call my-dir)
2: include $(CLEAR_VARS)
3: LOCAL_MODULE_TAGS := optional
4: LOCAL_SRC_FILES := $(call all-subdir-c-files)
5: LOCAL_MODULE := led_demo_test
6: include $(BUILD_EXECUTABLE)
7:
led_demo.h:
1: #ifndef __LED_DEMO_H__
2: #define __LED_DEMO_H__
3:
4: #define LED_ON _IOW(\'L\', 0, int)
5: #define LED_OFF _IOW(\'L\', 1, int)
6:
7: #endif
led_demo.c:
1: #include <stdio.h>
2: #include <sys/types.h>
3: #include <sys/stat.h>
4: #include <fcntl.h>
5: #include <stdlib.h>
6: #include <sys/ioctl.h>
7:
8: #include "led_demo.h"
9:
10: int main(int argc, const char *argv[])
11: {
12: int fd;
13: int i;
14:
15: fd = open("/dev/led_demo", O_RDWR);
16: if (fd < 0)
17: {
18: perror("failed to open.\\n");
19: exit(-1);
20: }
21:
22: while(1)
23: {
24: for(i=0; i<4; i++)
25: {
26: ioctl(fd, LED_OFF, i+1);
27: sleep(1);
28: ioctl(fd, LED_ON, i+1);
29: sleep(1);
30: ioctl(fd, LED_OFF, i+1);
31: sleep(1);
32: }
33: }
34:
35: close(fd);
36:
37: return 0;
38: }
编写完成后,在android-4.2.2_r1源码顶层目录下执行:
1: mmm ./external/led_demo/
2:
3: ./gen-img.sh
然后将顶层目录下新生成的system.img利用友善之臂提供的Minitools烧写到板子上。
烧写完成后,重启板子。
使用串口终端登陆板子,使用su命令进入root用户模式,然后进入/system/bin目录下,执行./led_demo_test,观察现象,可以看到,TINY4412的核心板上的四个LED灯循环亮灭。也可以使用wind7下的控制终端,用adb shell登陆板子,进行测试。
三、编写HAL代码
在hardware/libhardware/include/hardware/下创建文件led_demo_hal.h
在hardware/libhardware/modules/下创建目录led_demo_hal,然后进入led_demo_hal,创建两个文件,分别是Android.mk和
led_demo_hal.cpp。
下面是文件内容:
hardware/libhardware/include/hardware/led_demo_hal.h
1: #ifndef ANDROID_LED_DEMO_HAL_H
2: #define ANDROID_LED_DEMO_HAL_H
3:
4: #include <hardware/hardware.h>
5:
6: __BEGIN_DECLS
7:
8: #define LED_DEMO_HARDWARE_MODULE_ID "led_demo_hal" //模块ID 需要与下面的Android.mk中的LOCAL_MODULE 匹配,否则无法加载该HAL模块
9: #define LED_DEMO_HARDWARE_DEVICE_ID "led_demo" // 设备ID
10:
11:
12: struct led_demo_module_t
13: {
14: struct hw_module_t common;
15: };
16:
17: struct led_demo_device_t
18: {
19: struct hw_device_t common;
20: int fd;
21: int (*set_on)(struct led_demo_device_t *dev, int val); //用于控制LED,点亮第val个LED灯
22: int (*set_off)(struct led_demo_device_t *dev, int val); //熄灭第val个LED灯
23: };
24:
25: __END_DECLS
26:
27:
28: #endif
hardware/libhardware/modules/led_demo_hal/led_demo_hal.cpp
1: #define LOG_TAG "LED_DEMO_HALSTUB" //将来可以用DDMS的LogCat工具进行调试,便于查看打印信息
2:
3: #include <hardware/hardware.h>
4: #include <hardware/led_demo_hal.h>
5:
6: #include <fcntl.h>
7: #include <errno.h>
8:
9: #include <utils/Log.h>
10: #include <cutils/atomic.h>
11:
12:
13: #define DEVICE_NAME "/dev/led_demo" //设备结点,有Linux驱动程序自动创建
14: #define MODULE_NAME "led_demo"
15: #define MODULE_AUTHOR "pengdonglin137@163.com"
16:
17: #define LED_ON 0x40044c00 //点灯的命令,其实就是_IOW(\'L\', 0, int)的值,_IOW在编译时无法识别,待以后解决
18: #define LED_OFF 0x40044c01 //灭灯命令,其实就是_IOW(\'L\', 1, int)的值,可以在上面的led_demo.c中加打印,看一下这个值是多少
19:
20:
21: static int led_demo_open(const struct hw_module_t* module, const char* id,
22: struct hw_device_t** device);
23:
24: static int led_demo_close(struct hw_device_t* device);
25:
26: static int led_demo_set_on(struct led_demo_device_t *dev, int val);
27:
28: static int led_demo_set_off(struct led_demo_device_t *dev, int val);
29:
30:
31: static hw_module_methods_t led_demo_module_methods =
32: {
33: open:led_demo_open,
34: };
35:
36: struct led_demo_module_t HAL_MODULE_INFO_SYM =
37: {
38: common:{
39: tag:HARDWARE_MODULE_TAG,
40: version_major:1,
41: version_minor:0,
42: id:LED_DEMO_HARDWARE_MODULE_ID,
43: name:MODULE_NAME,
44: author:MODULE_AUTHOR,
45: methods:&led_demo_module_methods,
46: }
47: };
48:
49: static int led_demo_open(const struct hw_module_t* module, const char* id,
50: struct hw_device_t** device)
51: {
52: if(!strcmp(id, LED_DEMO_HARDWARE_DEVICE_ID))
53: {
54: struct led_demo_device_t *dev;
55:
56: dev = (struct led_demo_device_t *)malloc(sizeof(struct led_demo_device_t));
57: if(!dev)
58: {
59: ALOGE("Failed to alloc space for struct led_demo_device_t.");
60: return -EFAULT;
61: }
62:
63: memset(dev, 0, sizeof(struct led_demo_device_t));
64:
65: dev->common.tag =
HARDWARE_DEVICE_TAG
;
66: dev->common.version = 0;
67: dev->common.module = (struct hw_module_t *)module;
68: dev->common.close = led_demo_close;
69: dev->set_on = led_demo_set_on;
70: dev->set_off = led_demo_set_off;
71:
72: if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1)
73: {
74: ALOGE("Failed to open device %s ---- %s\\n.", DEVICE_NAME, strerror(errno));
75: free(dev);
76: return -EFAULT;
77: }
78:
79: *device = &(dev->common);
80:
81: ALOGE("Open device file %s successfully.", DEVICE_NAME);
82:
83: }
84:
85: return -EFAULT;
86: }
87:
88: static int led_demo_close(struct hw_device_t* device)
89: {
90: struct led_demo_device_t *led_device = (struct led_demo_device_t *)device;
91: if(led_device)
92: {
93: close(led_device->fd);
94: free(led_device);
95: }
96:
97: return 0;
98: }
99:
100: static int led_demo_set_on(struct led_demo_device_t *dev, int val)
101: {
102: if(!dev)
103: {
104: ALOGE("Null dev pointer.");
105: return -EFAULT;
106: }
107:
108: if(ioctl(dev->fd, LED_ON, val) < 0)
109: {
110: ALOGE("ioctl error --- %s.", strerror(errno));
111: return -EFAULT;
112: }
113:
114: return 0;
115:
116: }
117:
118: static int led_demo_set_off(struct led_demo_device_t *dev, int val)
119: {
120: if(!dev)
121: {
122: ALOGE("Null dev pointer.");
123: return -EFAULT;
124: }
125:
126: if(ioctl(dev->fd, LED_OFF, val) < 0)
127: {
128: ALOGE("ioctl error --- %s.", strerror(errno));
129: return -EFAULT;
130: }
131:
132: return 0;
133:
134: }
135:
hardware/libhardware/modules/led_demo_hal/Android.mk
1: LOCAL_PATH := $(call my-dir)
2: include $(CLEAR_VARS)
3: LOCAL_MODULE_TAGS := optional
4: LOCAL_PRELINK_MODULE := false
5: LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
6: LOCAL_SHARED_LIBRARIES := liblog
7: LOCAL_SRC_FILES := led_demo_hal.cpp
8: LOCAL_MODULE := led_demo_hal.default
9: include $(BUILD_SHARED_LIBRARY)
编写完成后,在Android源码的顶层目录执行:
mmm ./hardware/libhardware/modules/led_demo_hal/
最终out/target/product/tiny4412/system/lib/hw/目录下得到一个led_demo_hal.default.so文件。
下面处理一下硬件设备访问权限问题
在硬件抽象层模块中,我们是调用open函数来打开对应的设备文件的,在默认情况下,只有root用户才有权限访问系统的设备文件。但是一般的应用程序是没有root用户权限的。
解决办法,赋予root之外的其他用户访问设别文件/dev/led_demo的权限。做法如下:
在Android源码顶层目录下,修改system/core/rootdir/ueventd.rc,添加如下内容:
/dev/led_demo 0666 root root
修改了ueventd.rc文件后,需要重新编译Android源代码工程,编译时,文件system/core/rootdir/ueventd.rc会拷贝到out/target/product/tiny4412/root/下,并且最终打包在ramdisk.img中。对于友善之臂,执行完make -jN后,还需要执行./gen-img.sh脚本,然后在Android源码顶层目录中会生成ramdisk-u.img文件,利用MiniTools将其烧写到板子上。
四、编写Framework代码
- 定义硬件访问服务接口
在frameworks/base/core/java/android/os/创建文件ILed_demo_service.aidl,内容如下:
1: package android.os;
2:
3: interface ILed_demo_service
4: {
5: void led_set_ON(int val);
6: void led_set_OFF(int val);
7: }
然后,修改frameworks/base/Android.mk
1: LOCAL_SRC_FILES += \\
2: ......
3: core/java/android/os/IVibratorService.aidl \\
4: core/java/android/os/ILed_demo_service.aidl \\
最后,在Android源码顶层目录下执行
mmm ./frameworks/base/
编译后得到的framework.jar文件就包含了ILed_demo_service接口。
- 实现硬件访问服务
在frameworks/base/services/java/com/android/server/创建文件Led_demo_Service.java,内容如下:
1: package com.android.server;
2: import android.content.Context;
3: import android.os.ILed_demo_service;
4: import android.util.Slog;
5:
6:
7: public class Led_demo_Service extends ILed_demo_service.Stub
8: {
9: private static final String TAG = "Led_demo_Service"; //方便DDMS提供的LogCat工具看打印信息
10:
11: private int mPtr = 0;
12:
13: Led_demo_Service()
14: {
15: mPtr = init_native(); //硬件访问服务Led_demo_Service在启动时,会通过JNI方法init_native
16:
17: if(mPtr == 0)
18: {
19: Slog.e(TAG, "Failed to initialize Led demo Service.");
20: }
21: }
22:
23: public void led_set_ON(int val)
24: {
25: if(mPtr == 0)
26: {
27: Slog.e(TAG, "Led demo Service is not initialized.");
28: return;
29: }
30:
31: set_ON_native(mPtr, val);
32: }
33:
34: public void led_set_OFF(int val)
35: {
36: if(mPtr == 0)
37: {
38: Slog.e(TAG, "Led demo Service is not initialized.");
39: return;
40: }
41:
42: set_OFF_native(mPtr, val);
43: }
44:
45:
46: private static native int init_native();
47: private static native void set_OFF_native(int mPtr, int val);
48: private static native void set_ON_native(int mPtr, int val);
49:
50:
51: };
编写完成后,在Android源码顶层目录下执行:
mmm ./frameworks/base/services/java/
编译后得到的services.jar文件就包含有Led_demo_Service类。
五、编写JNI代码
在frameworks/base/services/jni/下创建文件com_android_server_led_demo_service.cpp,内容如下:
1: #define LOG_TAG "LED_DEMO_Service_JNI" //方便LogCat调试工具查看打印信息
2:
3: #include "jni.h"
4: #include "JNIHelp.h"
5: #include "android_runtime/AndroidRuntime.h"
6:
7: #include <utils/misc.h>
8: #include <utils/Log.h>
9: #include <hardware/hardware.h>
10: #include <hardware/led_demo_hal.h>
11:
12: #include <stdio.h>
13:
14:
15: namespace android
16: {
17:
18: static void led_demo_setOFF(JNIEnv *env, jobject clazz, jint ptr, jint value)
19: {
20: led_demo_device_t *device = (led_demo_device_t *)ptr;
21: if(!device)
22: {
23: ALOGE("Device led demo is not open.");
24: return ;
25: }
26:
27: int val = value;
28:
29: ALOGI("Set value %d to device led demo.", val);
30:
31: device->set_off(device, value);
32: }
33:
34: static void led_demo_setON(JNIEnv *env, jobject clazz, jint ptr, jint value)
35: {
36: led_demo_device_t *device = (led_demo_device_t *)ptr;
37: if(!device)
38: {
39: ALOGE("Device led demo is not open.");
40: return ;
41: }
42:
43: int val = value;
44:
45: ALOGI("Set value %d to device led demo.", val);
46:
47: device->set_on(device, value);
48: }
49:
50:
51: static inline int led_demo_device_open(const hw_module_t *module, struct led_demo_device_t **device)
52: {
53: return module->methods->open(module, LED_DEMO_HARDWARE_DEVICE_ID, (struct hw_device_t **)device);
54: }
55:
56:
57:
58: static jint led_demo_init(JNIEnv *env, jclass clazz)
59: {
60: struct led_demo_module_t *module;
61: struct led_demo_device_t *device;
62:
63:
64: ALOGI("Initializing HAL stub led ......");
65:
66: if(hw_get_module(
LED_DEMO_HARDWARE_MODULE_ID
, (const struct hw_module_t **)&module) == 0)
67: {
68: ALOGE("Device led demo found.");
69:
70: if(led_demo_device_open(&(module->common), &device))
71: {以上是关于我编写DS18b20程序,想显示温度在三个LED灯上,但LED一直数字不变,下面是程序,开发板TX-1C晶振 11.0592M的主要内容,如果未能解决你的问题,请参考以下文章