2015-4-1 22:49
ANDROID 应用控制 PWM
从硬件到软件
从C语言到JAVA语言
中间没有涉及HAL和Framework
GEC210 S5PV210
20150401 为什么骗我?
1st
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Kernel
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
* linux/drivers/char/gec210_pwm.c
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/err.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#define DEVICE_NAME "pwm"
#define PWM_IOCTL_SET_FREQ 1
#define PWM_IOCTL_STOP 0
#define NS_IN_1HZ (1000000000UL)
#define BUZZER_PWM_ID 0
#define BUZZER_PMW_GPIO S5PV210_GPD0(0)
static struct pwm_device *pwm4buzzer;
static struct semaphore lock;
static void pwm_set_freq(unsigned long freq) {
int period_ns = NS_IN_1HZ / freq;
pwm_config(pwm4buzzer, period_ns / 2, period_ns);
pwm_enable(pwm4buzzer);
}
static void pwm_stop(void) {
pwm_config(pwm4buzzer, 0, NS_IN_1HZ / 100);
pwm_disable(pwm4buzzer);
}
static int gec210_pwm_open(struct inode *inode, struct file *file) {
if (!down_trylock(&lock))
return 0;
else
return -EBUSY;
}
static int gec210_pwm_close(struct inode *inode, struct file *file) {
up(&lock);
return 0;
}
static long gec210_pwm_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case PWM_IOCTL_SET_FREQ:
if (arg == 0)
return -EINVAL;
pwm_set_freq(arg);
break;
case PWM_IOCTL_STOP:
default:
pwm_stop();
break;
}
return 0;
}
static struct file_operations gec210_pwm_ops = {
.owner = THIS_MODULE,
.open = gec210_pwm_open,
.release= gec210_pwm_close,
.unlocked_ioctl= gec210_pwm_ioctl,
};
static struct miscdevice gec210_misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &gec210_pwm_ops,
};
static int __init gec210_pwm_dev_init(void) {
int ret;
ret = gpio_request(BUZZER_PMW_GPIO, DEVICE_NAME);
if (ret) {
printk("request GPIO %d for pwm failed\n", BUZZER_PMW_GPIO);
return ret;
}
gpio_set_value(BUZZER_PMW_GPIO, 0);
s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_OUTPUT);
gpio_set_value(BUZZER_PMW_GPIO, 0);
pwm4buzzer = pwm_request(BUZZER_PWM_ID, DEVICE_NAME)
if (IS_ERR(pwm4buzzer)) {
printk("request pwm %d for %s failed\n", BUZZER_PWM_ID, DEVICE_NAME);
return -ENODEV;
}
pwm_stop();
gpio_set_value(BUZZER_PMW_GPIO, 0);
s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_SFN(2));
gpio_free(BUZZER_PMW_GPIO);
gpio_set_value(BUZZER_PMW_GPIO, 0);
init_MUTEX(&lock);
ret = misc_register(&gec210_misc_dev);
printk(DEVICE_NAME "\tinitialized\n");
return ret;
}
static void __exit gec210_pwm_dev_exit(void) {
pwm_stop();
misc_deregister(&gec210_misc_dev);
}
module_init(gec210_pwm_dev_init);
module_exit(gec210_pwm_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("GEC");【资料来自班主任周老师的光盘】
MODULE_DESCRIPTION("S5PV210 PWM Driver");
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/Kernel
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2nd
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
JNI
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#include <jni.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <utils/Log.h>
#define LOG_NDEBUG 0
#define LOG_TAG "pwm"
int fd=-1;
/ *
*此方法为上述Java文件openPwmDev方法的实现体
*native方法代表此方法实现体在C组件动态库完成
*/
JNIEXPORT void JNICALL Java_com_gec_pwmjnitest_activity_PwmJniTestActivity_openPwmDev(JNIEnv * env, jobject object)
{
LOGE("Java_com_gec_pwmjnitest_activity_PwmJniTestActivity_openPwmDev\n");
//打开PWM设备节点
fd=open("/dev/pwm",O_RDWR);
}
/*
*freq变量就是从Java层传入的频率
*通过ioctl调用驱动控制pwm频率
*/
JNIEXPORT void JNICALL Java_com_gec_pwmjnitest_activity_PwmJniTestActivity_opPwm(JNIEnv * env, jobject object,jint op,jlong freq)
{
LOGE("Java_com_gec_pwmjnitest_activity_PwmJniTestActivity_opPwm\n");
ioctl(fd, op , freq );
}
JNIEXPORT void JNICALL Java_com_gec_pwmjnitest_activity_PwmJniTestActivity_closePwmDev(JNIEnv * env, jobject object)
{
LOGE("Java_com_gec_pwmjnitest_activity_PwmJniTestActivity_closePwmDev\n");
//关闭PWM设备节点
close(fd);
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/JNI
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3rd
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Application
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
package com.gec.pwmjnitest.activity;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class PwmJniTestActivity extends Activity {
/** Called when the activity is first created. */
private EditText freId;
private Button btnStart,btnStop;
/ *
*静态加载C组件动态库(动态库名称是libpwmtest.so)
*注意动态库名称不是pwmtest.so,必须要在pwmtest前面加上lib
*/
static
{
System.loadLibrary("pwmtest");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
openPwnDev();
freId=(EditText)findViewById(R.id.freId);
btnStart=(Button)findViewById(R.id.btn_start_id);
btnStop=(Button)findViewById(R.id.btn_stop_id);
btnStart.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
String sfreq=freId.getText().toString();
//输入参数频率
opPwm(1,Long.parseLong(sfreq));
}
});
btnStop.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
String sfreq=freId.getText().toString();
opPwm(0,Long.parseLong(sfreq));
}
});
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
closePwmDev();
}
/*
*声明三个native方法
*native方法代表此方法实现体在C组件动态库完成
*op=1:代表启动蜂鸣器, op=0:代表停止蜂鸣, freq:输入蜂鸣器的频率
*/
public native void openPwmDev();
/ *
*op=1:代表启动蜂鸣器, op=0:代表停止蜂鸣, freq:输入蜂鸣器的频率
*/
public native void opPwm(int op,long freq);
public native void closePwmDev();
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/Application
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
步骤:
开发 Android 应用程序输入频率,控制蜂鸣器
掌握编写 Android 应用程序及通过 JNI 调用 C 函数控制 PWN
通过 Eclipse 开发 Android 应用程序界面
编写 JNI 程序的 C 语言文件
编写 Android.mk 文件
编译 Android 程序
本程序原理Android应用层界面开发由JAVA语言实现, 然后静态加载C语言组件动
态库, C语言组件动态库必须以JNI框架标准(Java Native Interface (JNI)标准是java
平台的一部分,它允许Java代码和其他语言写的代码进行交互。 JNI 是本地编程
接口,它使得在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语
言(如 C、 C++ 和汇编语言)编写的应用程序和库进行交互操作。),然后在C语言
组件动态库调用PWM驱动程序。
编写 PWMJNITESTACTIVITY.JAVA 源程序代码
工程目录新建 JNI 目录,编写 C 组件动态库 APPPWM.C 文件
根据 JNI1.0 调用规则
C 语言: appPwm.c 文件里面的
openPwmDev ------->Java_com_gec_pwmjnitest_activity_PwmJniTestActivity_openPwmDev
opPwn ------->Java_com_gec_pwmjnitest_activity_PwmJniTestActivity_opPwm
closePwnDev ------> Java_com_gec_pwmjnitest_activity_PwmJniTestActivity_closePwmDev
左边是在 JAVA 类声明的 native 成员方法,右边是 C 语言函数对应成员方法实现体
编写生成 JNI 动态库的配置文件 ANDROID.MK
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:=libpwmtest a
LOCAL_SRC_FILES:=appPwm.c b
LOCAL_C_INCLUDES+= \ c
$(JNI_H_INCLUDE)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_TAGS:= debug
include $(BUILD_SHARED_LIBRARY) d
其中abcd为注释,下同
a:生成C 动态库名称libpwmtest(JAVA层就是通过加载此库名称来实现互调)
b:编译C文件
c:加载jni库头文件
d:生成libpwmtest动态库,要跟Java静态加载的库名一致
编写应用工程 ANDROID.MK 文件
LOCAL_PATH:= $(call my-dir) a
include $(CLEAR_VARS) b
LOCAL_SRC_FILES := $(call all-subdir-java-files) c
LOCAL_PACKAGE_NAME:= PwmJniTest d
LOCAL_JNI_SHARED_LIBRARIES:= libpwmtest e
include $(BUILD_PACKAGE) f
include $(LOCAL_PATH)/jni/Android.mk g
# Use the folloing include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH)) h
a:一个Android.mk文件首先必须定义好LOCAL_PATH,获得当前目录
b:用来初始化Android.mk文件中” LOCAL_XXX” 的变量
c:编译Java文件
d:生成Android应用apk文件名称
e:生成JNI动态库libpwmtest
f:生成Android应用
g:编译jni目录里面的Android.mk文件
h:编译此工程里面所有的Android.mk文件
PWM 应用编译
将应用工程源代码(PwmJniTest)放到 Android-2.3.1\vendor\samsung\gec210\目录中, 先
对整个 Android-2.3.1 系统进行一次完整的编译。编译后按如下流程编译应用程序:
在 Android 源码目录下输入命令
#source build/envsetup.sh (生成的使用环境及环境中的命令)
#lunch 4(选择 full_gec210-eng 开发板)【full_gec210-eng 不知道这个是怎么来的】
#mmm vendor/samsung/gec210/ PwnJniTest(编译当前应用程序)
成功编译后会在 out/target/product/gec210/system/app/目录下生成对应的
PwmJniTest.apk 文件 【虽这个不曾尝试 但亲测编译过模拟器Goldfish版的 确实如此】
仅仅理论 木有实践
THE END
114