New file |
| | |
| | | # 一、安装及测试 |
| | | |
| | | ## 1. 安装apk软件 |
| | | |
| | | 通过**adb**安装apk软件: |
| | | |
| | | **方法一**: |
| | | |
| | | [Android adb启动任意app的几种方式_adb启动某个app的方法-CSDN博客](https://blog.csdn.net/ezconn/article/details/99885715) |
| | | |
| | | [彻底解决INSTALL_FAILED_UPDATE_INCOMPATIBLE的安装错误-CSDN博客](https://blog.csdn.net/fromVillageCoolBoy/article/details/134412425) |
| | | |
| | | ``` |
| | | 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 |
| | | ``` |
| | | |
| | | |
| | | |
| | | ## 2. 模块测试 |
| | | |
| | | 菜单:主要测试5个功能,分别是RS485通信,LED灯、CAN通信、蜂鸣器和ADC采样;点击对应的按钮进入相应的测试页面 |
| | | |
| | |  |
| | | |
| | | ### 2.1 测试RS485通信 |
| | | |
| | |  |
| | | |
| | | RS485通信的页面如上所示,可以根据需要选择不同的波特率、数据位、停止位、校验位和流控制,由于在硬件中已经固定了/dev/ttyS9为RS485通信的串口,因此在串口号的选择中只有/dev/ttyS9。 |
| | | |
| | | 1. 打开串口 |
| | | |
| | | 选择完串口的设置后,打开串口,若是由于权限不足则会弹出”添加权限“的提示。 |
| | | |
| | | ``` |
| | | chmod 666 /dev/ttyS9 |
| | | ``` |
| | | |
| | | |
| | | |
| | |  |
| | | |
| | | 若是串口打开成功,则会以绿色字体显示”/dev/ttyS9 OPEN +串口设置“(其中校验位和流控制为None时,表示为0),如下所示。 |
| | | |
| | |  |
| | | |
| | | 2. 发送数据 |
| | | |
| | | 在发送数据之前,需先将串口状态转换成”发送模式“,然后在发送框中输入数据,点击”发送“即完成发送数据过程。 |
| | | |
| | |  |
| | | |
| | | 3. 接收数据 |
| | | |
| | | 在接收数据之前,需先将串口状态转换成”接收模式“,在发送端发送数据,然后在APP中点击”接收“按钮,就能接收到发送端发送的数据。**一次发送一次接收**。RS485是半双工通信,因此,当要发送或是接收数据时,要先改变串口的状态。 |
| | | |
| | |  |
| | | |
| | | ### 2.2 测试LED灯 |
| | | |
| | | 当按下对应的按钮后,相应的灯发生亮灭的变化,其变化同样也会显示在界面中。 |
| | | |
| | | 例如,红灯亮起时,其上的图标也变成红色,而关闭红灯时,其上的图标变成灰色。同理,黄灯和绿灯也会发生类似的变化。 |
| | | |
| | |  |
| | | |
| | | 红灯亮 |
| | | |
| | |  |
| | | |
| | | ### 2.3 测试CAN通信 |
| | | |
| | |  |
| | | |
| | | 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 网络 |
| | | ``` |
| | | |
| | | 1. 发送数据 |
| | | |
| | | 在文本框中输入ID、DLC、Data后,点击”发送“按钮后,即可发送数据,在”发送区“会显示已发送的数据。 |
| | | |
| | |  |
| | | |
| | | 2. 接收数据 |
| | | |
| | | 点击”接收“按钮后,接收到的数据都会显示在”接收区“,和RS485不同,这里是”一直发送一次接收“。 |
| | | |
| | |  |
| | | |
| | | ### 2.4 测试蜂鸣器 |
| | | |
| | | 这里使用的蜂鸣器是无源蜂鸣器,用于测试pwm功能。通过设置周期和占空比可以让蜂鸣器发声。 |
| | | |
| | | 若是由于权限问题无法打开PWM,则会弹出”添加export权限“的提示 |
| | | |
| | | ``` |
| | | chmod 777 /sys/class/pwm/pwmchip2/* |
| | | ``` |
| | | |
| | | |
| | | |
| | |  |
| | | |
| | | 继续运行出现”添加pwm0权限”的提示 |
| | | |
| | | ``` |
| | | chmod 777 /sys/class/pwm/pwmchip2/pwm0/* |
| | | ``` |
| | | |
| | | |
| | | |
| | |  |
| | | |
| | | 如下所示,设置周期为1000000,周期50000,点击”播放“,成功运行出现弹窗提醒 |
| | | |
| | |  |
| | | |
| | | 暂停播放 |
| | | |
| | |  |
| | | |
| | | |
| | | |
| | | ### 2.5 测试ADC采样 |
| | | |
| | | ADC的串口设置和RS485类似,只不过ADC通信中所使用的是十六进制数据。 |
| | | |
| | | 串口设置:波特率(115200),数据位(8),停止位(1),校验位(None),流控制(None) |
| | | |
| | |  |
| | | |
| | | 打开串口后,在操作设置中选择电流或电压,选择要读取数据的通道。 |
| | | |
| | | 例如,读取第0通路的电流 |
| | | |
| | |  |
| | | |
| | | 读取第0通道的电压 |
| | | |
| | |  |
| | | |
| | | 其他通路的操作和上面类似 |
| | | |
| | | # 二、各模块接口函数说明 |
| | | |
| | | 每个模块的功能由四个文件共同组成: |
| | | |
| | | 1. xxxActivity.java |
| | | |
| | | UI界面的功能实现。位于:\app\src\main\java\com\example\serial\xxxActivity.java |
| | | |
| | | 2. xxxControl.java |
| | | |
| | | API函数声明。位于:\app\src\main\java\com\example\serial\xxxControl.java |
| | | |
| | | 3. xxx_control.cpp |
| | | |
| | | API函数实现。位于:\app\src\main\cpp\xxx_control.cpp |
| | | |
| | | 4. activity_xxx.xml |
| | | |
| | | UI界面设计。位于:\app\src\main\res\layout\activity_xxx.xml |
| | | |
| | | ## 1. RS485 |
| | | |
| | | ### 1.1 RS485Activity.java |
| | | |
| | | \app\src\main\java\com\example\serial\RS485Activity.java |
| | | |
| | | 实现RS485通信界面中各个按钮的跳转,数据的获取。 |
| | | |
| | | ### 1.2 RS485Control.java |
| | | |
| | | \app\src\main\java\com\example\serial\RS485Control.java |
| | | |
| | | 1. 打开串口并设置串口的波特率、数据位、校验位、停止位、流控制。 |
| | | |
| | | ```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**。 |
| | | |
| | | 2. 关闭串口 |
| | | |
| | | ```java |
| | | public static native int closeSerialPort(); |
| | | ``` |
| | | |
| | | 成功返回0,失败返回-1。 |
| | | |
| | | 3. 发送数据 |
| | | |
| | | ```java |
| | | public static native int sendToPort(String msg, int len); |
| | | ``` |
| | | |
| | | msg:发送的数据,String类型;len:发送数据的长度。成功返回>0,失败返回<0。 |
| | | |
| | | 4. 接收数据 |
| | | |
| | | ```java |
| | | public static native String recvFromPort(int len, int timeout); |
| | | ``` |
| | | |
| | | len:表示接收数据的长度;timeout:超时时间,单位为ms。**成功返回接收到的数据,失败返回NULL**。 |
| | | |
| | | 5. 修改串口状态 |
| | | |
| | | ```java |
| | | public static native int changeState(int state); |
| | | ``` |
| | | |
| | | RS485是半双工通信,发送和接收取决于gpiochip4 26引脚的高低电平,设置为低电平发送,高电平接收。成功返回0,失败返回-1. |
| | | |
| | | ### 1.3 rs485_control.cpp |
| | | |
| | | \app\src\main\cpp\rs485_control.cpp。此文件包含RS485Control.java中函数的实现。 |
| | | |
| | | 1. 串口结构体: |
| | | |
| | | ```C |
| | | typedef struct comport_s |
| | | { |
| | | char devname[12]; |
| | | unsigned int databit, parity, stopbit, flowctrl; |
| | | long baudrate; |
| | | |
| | | int fd; |
| | | int frag_size; |
| | | }comport_t; |
| | | ``` |
| | | |
| | | 2. 获取波特率 |
| | | |
| | | ```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) |
| | | |
| | | ## 2. LED |
| | | |
| | | ### 2.1 LedActivity.java |
| | | |
| | | 实现按钮的功能 |
| | | |
| | | ### 2.2 LedControl.java |
| | | |
| | | ```Java |
| | | public static native int ledCtrl(int which, int status); |
| | | ``` |
| | | |
| | | which:表示要操作的灯的位置,取值为0,1,2;status:表示灯的状态,0表示开灯,1表示关灯。(低电平点亮,高电平关闭)。成功返回0,失败返回一个小于0的负数。 |
| | | |
| | | ### 2.3 led_control.cpp |
| | | |
| | | ```C |
| | | 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“; |
| | | |
| | | ```C |
| | | led_gpio_t leds[LED_MAX] = |
| | | { |
| | | {LED_R, 18, "red", NULL}, |
| | | {LED_Y, 22, "yellow", NULL}, |
| | | {LED_G, 20, "green", NULL}, |
| | | }; |
| | | ``` |
| | | |
| | | 预先定义数组用来存放每个灯所对应的信息。 |
| | | |
| | | ## 3. CAN |
| | | |
| | | ### 3.1 CanActivity.java |
| | | |
| | | UI界面的功能实现 |
| | | |
| | | ### 3.2 CanControl.java |
| | | |
| | | 1. 发送数据 |
| | | |
| | | ```java |
| | | public static native int sendMessage(String id, String dlc, String data, String ifname); |
| | | ``` |
| | | |
| | | 待发送的CAN帧由id,dlc,data三部分组成,ifname表示can设备的名称(can0或can1)。成功返回0,失败返回小于0的负数。 |
| | | |
| | | 2. 接收数据 |
| | | |
| | | ```java |
| | | public static native String receiveMessage(String ifname); |
| | | ``` |
| | | |
| | | ifname表示can设备的名称(can0 或can1).成功返回接收到的数据,失败返回NULL。返回的数据格式为”ID=xx DLC=xx Data=xx xx xx xx“。 |
| | | |
| | | ### 3.3 can_control.cpp |
| | | |
| | | CanControl.java中的函数实现 |
| | | |
| | | ## 4. PWM-蜂鸣器 |
| | | |
| | | ### 4.1 BuzzerActivity.java |
| | | |
| | | UI界面的功能实现 |
| | | |
| | | ### 4.2 BuzzerControl.java |
| | | |
| | | 1. 打开PWM |
| | | |
| | | ```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. |
| | | |
| | | 2. 配置PWM |
| | | |
| | | ```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. |
| | | |
| | | ### 4.3 buzzer_control.cpp |
| | | |
| | | BuzzerControl.java的函数实现 |
| | | |
| | | ## 5. ADC采样 |
| | | |
| | | ### 5.1 AdcActivity.java |
| | | |
| | | UI界面的功能实现 |
| | | |
| | | ### 5.2 AdcControl.java |
| | | |
| | | 1. 打开串口 |
| | | |
| | | ```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时表示打开串口的权限不够。 |
| | | |
| | | 2. 关闭串口 |
| | | |
| | | ```Java |
| | | public static native int closeComport(); |
| | | ``` |
| | | |
| | | 成功返回0,失败返回小于0的负数。 |
| | | |
| | | 3. 发送数据 |
| | | |
| | | ```java |
| | | public static native int sendToPort(String operate, String channel); |
| | | ``` |
| | | |
| | | 向串口发送数据,operate:操作电流或电压;channel:欲操作的通道。 |
| | | |
| | | 下图是ADC串口协议,通过添加类型和通道号即可形成完整的读指令报文。 |
| | | |
| | |  |
| | | |
| | | 4. 接收数据 |
| | | |
| | | ```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。 |
| | | |
| | | ### 5.3 adc_control.cpp |
| | | |
| | | ```cpp |
| | | typedef struct comport_s |
| | | { |
| | | char devname[12]; |
| | | unsigned int databit, parity, stopbit, flowctrl; |
| | | long baudrate; |
| | | |
| | | int fd; |
| | | int frag_size; |
| | | }comport_t; |
| | | ``` |
| | | |
| | | 串口配置结构体。 |
| | | |
| | | ```cpp |
| | | static speed_t getBaudRate(int baudRate) |
| | | ``` |
| | | |
| | | 将int类型的波特率转换成可以识别的波特率. |
| | | |
| | | ```cpp |
| | | 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`. |
| | | |
| | | ```C |
| | | 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`库。 |
| | | |