在之前的分享 【米尔-TI AM62x开发板-试用评测】使用Yocto工具构建开发板完整镜像和SDK工具 中,已经讲过完整镜像和SDK工具的构建全过程,这篇分享,就使用构建的SDK工具,进行应用基础开发。
一、硬件了解
在米尔-TI AM62x开发板开发板上,提供了三个按键,1个可以被在程序中使用:
另外,开发板上还提供了多个LED,具体如下:
后面的程序中,就使用上面的User按键和D53、D54 LED。
二、系统挂载了解
在手册中,给出了按键的测试方式:
可以使用下面的命令,进行测试:
hexdump /dev/input/event0
执行后,按下按键和松开,就会有对应的输出。
另外,手册中也给出了LED的测试方法:
登录系统后,可以查看到具体的LED挂载情况:
通过上面的系统信息我们可以得到:
下面,就进行程序编写,进行调用和控制。
三、按键程序
按键通过系统input的event来进行获取,具体的代码如下:
#include <stdio.h>
#include <linux/input.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// gpio-keys
#define DEV_PATH "/dev/input/event0"
// 主函数
int main()
{
int keys_fd;
char ret[2];
struct input_event t;
keys_fd=open(DEV_PATH, O_RDONLY);
if(keys_fd <= 0)
{
printf("open "DEV_PATH" device error!\n");
return -1;
}
while(1)
{
if(read(keys_fd, &t, sizeof(t)) == sizeof(t))
{
if(t.type==EV_KEY)
if(t.value==0 || t.value==1)
{
printf("key %d %s\n", t.code, (t.value) ? "Pressed" : "Released");
if(t.code == KEY_ESC)
break;
}
}
}
close(keys_fd);
return 0;
}
在上述代码中,打开设备 /dev/input/event0 ,然后读取事件信息,如果事件信息为EV_KEY,则判断其值,根据值来判断,是按下1还是松开0
将上述代码保存到key.c,然后按照下面的步骤进行编译。
首次进行新应用开发的话,需要在开发环境,先执行如下命令安装SDK工具链:
./myd-ym62x-yocto/oe-layersetup/build/arago-tmp-default-glibc/deploy/sdk/arago-2023.04-toolchain-2023.04.sh
其中arago-2023.04-toolchain-2023.04.sh即为之前编译的SDK工具,安装路径为/opt/arago-2023.04/
然后使用SDK工具进行编译:
source /opt/arago-2023.04/environment-setup-aarch64-oe-linux
$CC key.c -o key
编译完成,将程序部署到开发板上,运行,然后按键,结果如下:
四、LED控制
下面的程序,控制D53、D54交替点亮:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
// LED 引脚
#define SYSFS_GPIO_LED_1_VAL "/sys/class/leds/am62-sk:d53/brightness"
#define SYSFS_GPIO_LED_2_VAL "/sys/class/leds/am62-sk:d54/brightness"
#define SYSFS_GPIO_LED_VAL_H "1"
#define SYSFS_GPIO_LED_VAL_L "0"
int main()
{
int fd1;
int fd2;
int count = 30;
// 打开LED GPIO
fd1 = open(SYSFS_GPIO_LED_1_VAL, O_RDWR);
if (fd1 == -1)
{
printf("ERR: gpio1 open error.\n");
return EXIT_FAILURE;
}
fd2 = open(SYSFS_GPIO_LED_2_VAL, O_RDWR);
if (fd2 == -1)
{
printf("ERR: gpio2 open error.\n");
return EXIT_FAILURE;
}
while (count)
{
count--;
write(fd1, SYSFS_GPIO_LED_VAL_H, sizeof(SYSFS_GPIO_LED_VAL_H));
write(fd2, SYSFS_GPIO_LED_VAL_L, sizeof(SYSFS_GPIO_LED_VAL_L));
usleep(1000000);
write(fd1, SYSFS_GPIO_LED_VAL_L, sizeof(SYSFS_GPIO_LED_VAL_L));
write(fd2, SYSFS_GPIO_LED_VAL_H, sizeof(SYSFS_GPIO_LED_VAL_H));
usleep(1000000);
}
close(fd1);
close(fd2);
return 0;
}
上述代码逻辑较为简单,就是打开两个LED对应的设备,然后分别写入0、1,从而控制亮灭。
source /opt/arago-2023.04/environment-setup-aarch64-oe-linux
$CC led.c -o led
将上述代码保存到led.c,然后按照key.c的步骤进行编译,再部署到开发板上,就能控制LED了。
五、按键控制LED
在这一步中,我对按键的时间进行检测,从而判断是长按还是短按。
短按控制LED1,长按控制LED2。每个LED,第一次按键点亮,第二次按键熄灭。
要检测按键时长,可以先测试下面的程序,使用系统clock_gettime()调用来获取运行时间:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
long getTimeNs()
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME,&ts);
return ts.tv_sec*1000000000+ts.tv_nsec;
}
// 测试函数
void Test()
{
int i,j;
for(i=1000;i>0;i--)
for(j=2000;j>0;j--);
}
// 主函数
int main()
{
clock_t start, stop;//定义2个变量用来存放开始和结束时间
double duration;
start = getTimeNs();//开始计时
Test(); //被测函数
stop = getTimeNs(); //结束计时
duration = ((double)(stop - start))/1000000000;//计算以秒为单位的运行时间,(结束时间-开始时间)
printf("测试函数耗费时间为 %0.6f 秒\n",duration);
return 0;
}
将上述代码保存为time_calc.c,编译运行后部署到开发板,运行结果如下:
结合上面的程序,通过按键时长是否超过1秒,来判断是否是否长按,具体代码如下:
#include <stdio.h>
#include <linux/input.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <stdbool.h>
// gpio-keys
#define DEV_PATH "/dev/input/event0"
#define TIME_LONG 1
long getTimeNs()
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME,&ts);
return ts.tv_sec*1000000000+ts.tv_nsec;
}
// 主函数
int main()
{
clock_t start, stop;//定义2个变量用来存放开始和结束时间
double duration;
bool status;
int keys_fd;
char ret[2];
struct input_event t;
keys_fd=open(DEV_PATH, O_RDONLY);
if(keys_fd <= 0)
{
printf("open "DEV_PATH" device error!\n");
return -1;
}
status = false;
start = 0;
stop = 0;
while(1)
{
if(read(keys_fd, &t, sizeof(t)) == sizeof(t))
{
if(t.type==EV_KEY)
if(t.value==0 || t.value==1)
{
printf("key %d %s\n", t.code, (t.value) ? "Pressed" : "Released");
if(t.code==0x100) {
if(t.value) {
if(!status) {
status = true;
start = getTimeNs();
}
} else {
status = false;
stop = getTimeNs();
duration = ((double)(stop - start))/1000000000;//计算以秒为单位的运行时间,(结束时间-开始时间)
printf("按键时长 %0.6f 秒\n",duration);
if(duration>TIME_LONG) {
printf("长按\n");
} else {
printf("短按\n");
}
}
}
if(t.code == KEY_ESC)
break;
printf("\n");
}
}
}
close(keys_fd);
return 0;
}
将上述代码保存为key_short_long.c,编译运行后部署到开发板,运行结果如下:
通过按键的时长,程序会根据其判断是否长按短按。
最后,结合LED控制的程序,通过短按控制LED1、长按控制LED2,具体程序如下:
#include <stdio.h>
#include <linux/input.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <stdbool.h>
// gpio-keys
#define DEV_PATH "/dev/input/event0"
#define TIME_LONG 1
// LED 引脚
#define SYSFS_GPIO_LED_1_VAL "/sys/class/leds/am62-sk:d53/brightness"
#define SYSFS_GPIO_LED_2_VAL "/sys/class/leds/am62-sk:d54/brightness"
#define SYSFS_GPIO_LED_VAL_H "1"
#define SYSFS_GPIO_LED_VAL_L "0"
long getTimeNs()
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME,&ts);
return ts.tv_sec*1000000000+ts.tv_nsec;
}
// 主函数
int main()
{
clock_t start, stop;//定义2个变量用来存放开始和结束时间
double duration;
bool status;
int keys_fd;
char ret[2];
struct input_event t;
int fd1;
int fd2;
bool status1;
bool status2;
// 打开LED GPIO
fd1 = open(SYSFS_GPIO_LED_1_VAL, O_RDWR);
if (fd1 == -1)
{
printf("ERR: gpio1 open error.\n");
return EXIT_FAILURE;
}
fd2 = open(SYSFS_GPIO_LED_2_VAL, O_RDWR);
if (fd2 == -1)
{
printf("ERR: gpio2 open error.\n");
return EXIT_FAILURE;
}
status1 = false;
status2 = false;
write(fd1, SYSFS_GPIO_LED_VAL_L, sizeof(SYSFS_GPIO_LED_VAL_L));
write(fd2, SYSFS_GPIO_LED_VAL_L, sizeof(SYSFS_GPIO_LED_VAL_L));
keys_fd=open(DEV_PATH, O_RDONLY);
if(keys_fd <= 0)
{
printf("open "DEV_PATH" device error!\n");
return -1;
}
status = false;
start = 0;
stop = 0;
while(1)
{
if(read(keys_fd, &t, sizeof(t)) == sizeof(t))
{
if(t.type==EV_KEY)
if(t.value==0 || t.value==1)
{
printf("key %d %s\n", t.code, (t.value) ? "Pressed" : "Released");
if(t.code==0x100) {
if(t.value) {
if(!status) {
status = true;
start = getTimeNs();
}
} else {
stop = getTimeNs();
duration = ((double)(stop - start))/1000000000;//计算以秒为单位的运行时间,(结束时间-开始时间)
printf("按键时长 %0.6f 秒\n",duration);
if(duration>TIME_LONG) {
printf("长按:操作LED2\n");
status2 = !status2;
if(status2) {
write(fd2, SYSFS_GPIO_LED_VAL_H, sizeof(SYSFS_GPIO_LED_VAL_H));
} else {
write(fd2, SYSFS_GPIO_LED_VAL_L, sizeof(SYSFS_GPIO_LED_VAL_L));
}
} else {
printf("短按:操作LED1\n");
status1 = !status1;
if(status1) {
write(fd1, SYSFS_GPIO_LED_VAL_H, sizeof(SYSFS_GPIO_LED_VAL_H));
} else {
write(fd1, SYSFS_GPIO_LED_VAL_L, sizeof(SYSFS_GPIO_LED_VAL_L));
}
}
status = false;
}
}
if(t.code == KEY_ESC)
break;
printf("\n");
}
}
}
close(fd1);
close(fd2);
close(keys_fd);
return 0;
}
将上述代码保存为button_led.c,编译运行后部署到开发板,运行结果如下:
六、总结
以上使用米尔提供的构建环境,构建出来的SDK工具,进行应用的基础开发。
SDK工具有了,那么其他的开发,大部分就和通常Linux环境下面的开发类似了。
当然,有一些根据系统硬件情况的不同,还是会有差异的,后续进一步开发过程中,再逐步分享。