通过**adb**安装apk软件:
方法一:
Android adb启动任意app的几种方式_adb启动某个app的方法-CSDN博客
彻底解决INSTALL_FAILED_UPDATE_INCOMPATIBLE的安装错误-CSDN博客
adb root
adb install -r apk文件的位置
如:adb install -r E:\lingyun\RK3568\rk3568_app1.0\rk3568.apk
出现:Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE: Existing package com.example.serial signatures do not match newer version; ignoring!表示系统中已经安装过这个软件,需要把之前的卸载后再重新安装
adb remount
adb pull /data/system/packages.xml
拉取了packages.xml后,打开该文件将涉及com.example.serial的地方都删除
adb push packages.xml /data/system
adb uninstall com.example.serial
adb remount
adb install -r -g E:\lingyun\RK3568\rk3568_app1.0\rk3568.apk
方法二:
adb root
adb remount
adb push ...\rk3568.apk /system/app
adb shell chmod 666 /system/app/rk3568.apk
adb reboot
重启开启APP
adb shell am start -n com.example.serial/.MainActivity
com.example.serial是包名
关闭APP
adb shell am force-stop com.example.serial
菜单:主要测试5个功能,分别是RS485通信,LED灯、CAN通信、蜂鸣器和ADC采样;点击对应的按钮进入相应的测试页面
RS485通信的页面如上所示,可以根据需要选择不同的波特率、数据位、停止位、校验位和流控制,由于在硬件中已经固定了/dev/ttyS9为RS485通信的串口,因此在串口号的选择中只有/dev/ttyS9。
选择完串口的设置后,打开串口,若是由于权限不足则会弹出”添加权限“的提示。
chmod 666 /dev/ttyS9
若是串口打开成功,则会以绿色字体显示”/dev/ttyS9 OPEN +串口设置“(其中校验位和流控制为None时,表示为0),如下所示。
在发送数据之前,需先将串口状态转换成”发送模式“,然后在发送框中输入数据,点击”发送“即完成发送数据过程。
在接收数据之前,需先将串口状态转换成”接收模式“,在发送端发送数据,然后在APP中点击”接收“按钮,就能接收到发送端发送的数据。**一次发送一次接收**。RS485是半双工通信,因此,当要发送或是接收数据时,要先改变串口的状态。
当按下对应的按钮后,相应的灯发生亮灭的变化,其变化同样也会显示在界面中。
例如,红灯亮起时,其上的图标也变成红色,而关闭红灯时,其上的图标变成灰色。同理,黄灯和绿灯也会发生类似的变化。
红灯亮
CAN通信的页面如上所示,可根据需要选择不同的can,设置发送数据帧的ID、DLC、Data。
注:在进行CAN通信前,还需进行以下设置(将can1替换成can0即可操作can0)
ip link set can1 down //关闭 can 网络
ip link set can1 up type can bitrate 800000 //设置 can1 的波特率为 800kbps,can 网络波特率最大值为 1mbps
ip link set can1 up type can //打开 can 网络
在文本框中输入ID、DLC、Data后,点击”发送“按钮后,即可发送数据,在”发送区“会显示已发送的数据。
点击”接收“按钮后,接收到的数据都会显示在”接收区“,和RS485不同,这里是”一直发送一次接收“。
这里使用的蜂鸣器是无源蜂鸣器,用于测试pwm功能。通过设置周期和占空比可以让蜂鸣器发声。
若是由于权限问题无法打开PWM,则会弹出”添加export权限“的提示
chmod 777 /sys/class/pwm/pwmchip2/*
继续运行出现”添加pwm0权限”的提示
chmod 777 /sys/class/pwm/pwmchip2/pwm0/*
如下所示,设置周期为1000000,周期50000,点击”播放“,成功运行出现弹窗提醒
暂停播放
ADC的串口设置和RS485类似,只不过ADC通信中所使用的是十六进制数据。
串口设置:波特率(115200),数据位(8),停止位(1),校验位(None),流控制(None)
打开串口后,在操作设置中选择电流或电压,选择要读取数据的通道。
例如,读取第0通路的电流
读取第0通道的电压
其他通路的操作和上面类似
每个模块的功能由四个文件共同组成:
UI界面的功能实现。位于:\app\src\main\java\com\example\serial\xxxActivity.java
API函数声明。位于:\app\src\main\java\com\example\serial\xxxControl.java
API函数实现。位于:\app\src\main\cpp\xxx_control.cpp
UI界面设计。位于:\app\src\main\res\layout\activity_xxx.xml
\app\src\main\java\com\example\serial\RS485Activity.java
实现RS485通信界面中各个按钮的跳转,数据的获取。
\app\src\main\java\com\example\serial\RS485Control.java
java public static native int openSerialPort(String path, long baudRate, int dataBits, int parity, int stopBits, int flowControl, int maxLen);
path: 串口地址(/dev/ttyS9),baudRate:串口的波特率,dataBits:数据位,parity:校验位,stopBits:停止位,flowControl:流控制(通常设置为0,表示None)。**成功返回0,失败返回负数, 打开串口的权限不足返回1**。
java public static native int closeSerialPort();
成功返回0,失败返回-1。
java public static native int sendToPort(String msg, int len);
msg:发送的数据,String类型;len:发送数据的长度。成功返回>0,失败返回<0。
java public static native String recvFromPort(int len, int timeout);
len:表示接收数据的长度;timeout:超时时间,单位为ms。**成功返回接收到的数据,失败返回NULL**。
java public static native int changeState(int state);
RS485是半双工通信,发送和接收取决于gpiochip4 26引脚的高低电平,设置为低电平发送,高电平接收。成功返回0,失败返回-1.
\app\src\main\cpp\rs485_control.cpp。此文件包含RS485Control.java中函数的实现。
```C
typedef struct comport_s
{
char devname[12];
unsigned int databit, parity, stopbit, flowctrl;
long baudrate;
int fd;
int frag_size;
}comport_t;
```
C static speed_t getBaudRate(int baudRate);
将int类型的波特率转换成speed_t类型。
包含:0、50、75、110、134、150、200、300、600、1200、1800、2400、4800、9600、19200、38400、57600、115200、230400、460800、500000、576000、921600、1000000、1152000、1500000、2000000、2500000、3000000、3500000、4000000;若是baudRate不在这个范围内,则返回-1。
(有关RS485的UI设计位于\app\src\main\res\layout\activity_rs485.xml)
实现按钮的功能
public static native int ledCtrl(int which, int status);
which:表示要操作的灯的位置,取值为0,1,2;status:表示灯的状态,0表示开灯,1表示关灯。(低电平点亮,高电平关闭)。成功返回0,失败返回一个小于0的负数。
enum
{
LED_R=0,
LED_Y,
LED_G,
LED_MAX,
};
typedef struct led_gpio_s
{
int idx;
int gpio;
const char *desc;
struct gpiod_line *line;
}led_gpio_t;
定义结构体,gpio表示引脚编号,如红灯对应的是gpiochip0 18,那么gpio=18;desc:表示对该引脚的描述,可以表示为”red“;
led_gpio_t leds[LED_MAX] =
{
{LED_R, 18, "red", NULL},
{LED_Y, 22, "yellow", NULL},
{LED_G, 20, "green", NULL},
};
预先定义数组用来存放每个灯所对应的信息。
UI界面的功能实现
java public static native int sendMessage(String id, String dlc, String data, String ifname);
待发送的CAN帧由id,dlc,data三部分组成,ifname表示can设备的名称(can0或can1)。成功返回0,失败返回小于0的负数。
java public static native String receiveMessage(String ifname);
ifname表示can设备的名称(can0 或can1).成功返回接收到的数据,失败返回NULL。返回的数据格式为”ID=xx DLC=xx Data=xx xx xx xx“。
CanControl.java中的函数实现
UI界面的功能实现
java public native static int pwmOpen(String id);
打开需要操作的pwm设备,例如需要操作的pwm为: /sys/class/pwm/pwmchip2,因此id=”2“,需要操作的是/sys/class/pwm/pwmchip2/pwm0,会先判断pwm0是否存在,不存在就会导入。成功返回0,失败返回小于0的负数,打开设备的权限不足返回1.
java public native static int pwmConfig(String attr, String val);
以/sys/class/pwm/pwmchip2为例,通过配置/sys/class/pwm/pwmchip2/pwm0的period和duty_cycle可以让该PWM输出不同的方波。attr表示需要配置的文件名(period或duty_cycle),val表示写入该文件的值。打开设备的权限不足返回1,配置的值无效返回2.
BuzzerControl.java的函数实现
UI界面的功能实现
Java public static native int openComport(String path, long baudRate, int dataBits, int parity, int stopBits, int flowControl);
path: 串口(/dev/ttyS6); baudRate: 波特率(115200);dataBits:数据位(8);parity:奇偶校验(0表示None,1表示奇校验,2表示偶校验);stopBits:停止位(1);flowControl:流控制(0表示无,1表示硬件流,2表示软件流)。成功返回0,失败返回小于0的负数,当返回1时表示打开串口的权限不够。
Java public static native int closeComport();
成功返回0,失败返回小于0的负数。
java public static native int sendToPort(String operate, String channel);
向串口发送数据,operate:操作电流或电压;channel:欲操作的通道。
下图是ADC串口协议,通过添加类型和通道号即可形成完整的读指令报文。
Java public static native String recvFromPort(int len, int timeout);
从串口读取数据并返回。len:表示读取数据的最大长度;timeout:超时时间(单位:ms)。成功返回读取到的数据,失败返回NULL。
根据接收到的数据即可计算其所对应的电流或电压。
设接收的数据为:AA 55 01 00 95 01 BB 71 //01 95 -> 405 单位0.01mA,即4.05mA,其中AA 55为报文头,01表示电流,00表示通道0,95 01表示通道0的电流值,BB 71表示CRC校验码。由于是低字节先发送,因此在计算电流值时,实际的顺序是 01 95 => 电流 = 0*16^3 + 1*16^2 + 9*16^1 + 5*16^0 = 405, 单位是0.01mA,最后得到电流值为4.05mA。
typedef struct comport_s
{
char devname[12];
unsigned int databit, parity, stopbit, flowctrl;
long baudrate;
int fd;
int frag_size;
}comport_t;
串口配置结构体。
static speed_t getBaudRate(int baudRate)
将int类型的波特率转换成可以识别的波特率.
unsigned short crc_modbus(unsigned char *ptr, int len)
根据十六进制值计算CRC16校验码。ptr:需要计算的十六进制字符数组;len:表示需要计算的字符长度。以读指令为例,设unsigned char read[6] = {0xAA, 0x55, 0x01, 0x00}
,那么它的CRC校验码为uint16_t crc = crc_modbus(read, 4)
, 完整的读指令为read[4] = crc & 0xFF; read[5] = (crc >> 8) & 0xFF
.
void calculate(char *result, unsigned char *data, int len)
计算ADC返回结果的数值,result用于存放返回的结果,格式为"电流/电压-通道X=....";data表示ADC串口返回的十六进制结果;len表示data的数据长度。
openComport
, closeComport
, sendToPort
, recvFromPort
的函数实现。
ndk:25.1.8937393
CMake:3.22.1
, 3.18.1
外部配置:libgpiod
库。