一、简介
1.实现功能
能够实时读取JetsonNano开发板GPIO口的电平信号,并将读到的电平信号返回到Qt主程序中
2.环境工具
开发板:JetsonNano
系统:Ubuntu
语言:C/C++,python
二、准备工作
1.JetsonNano开发板GPIO口介绍
GPIO.png
JetsonNano的引脚与树莓派相似,有两种定义模式,一种是BCM编码,对应的是GPIO功能编码(图中Sysfs GPIO),一种是物理引脚编码,即BOARD编码(图中Pin)。
2.查看开发板是否预装了GPIO口的运行环境
1 | cd /opt/nvidia/jetson-gpio |
一般默认是安装好的,如果没有安装好,依次执行一下命令
1 2 3 4 | 安装pip工具 sudo apt-get update sudo apt-get install python-pip sudo apt-get install python3-pip |
1 2 3 | 下载安装Jetson.GPIO库: sudo pip install Jetson.GPIO sudo pip3 install Jetson.GPIO |
1 2 3 4 5 6 7 8 9 10 | 设置用户权限: sudo groupadd -f -r gpio sudo usermod -a -G gpio your_user_name 注意:这里的your_user_name需要改成你自己的账号名,不然库无法正常使用 将99-gpio.rules文件复制到rules.d目录 sudo cp lib/python/Jetson/GPIO/99-gpio.rules /etc/udev/rules.d/ 重载rules规则来让文件生效 sudo udevadm control --reload-rules && sudo udevadm trigger |
以上方法参照https://www.waveshare.net/study/portal.php?mod=view&aid=882这篇文章,我自己并没有实际操作过,因为我得板子里已经是预装好了的
3查看一些官方示例
官方给出了一些关于GPIO口的输入输出PWM控制等的简单例子,进入文件夹可查看
1 | cd /opt/nvidia/jetson-gpio/samples/ |
三、使用Qt调用Python
1.将Python的include和lib添加到Qt工程的.pro文件中
找到Python的安装路径,在Qt的.pro文件中添加include和lib,如图在.pro的最后添加即可,我这里为了不出错,把两个版本的python库都加进来了,其实加3.6应该就可以,加进去之后记得Ctrl+S保存一下,或者直接编译一下
.pro文件.png
2.在qt中加入头文件#include
如果第一步没问题的话,#include
3.根据自己的需要编写python脚本
我这里要实现的功能是实时读取35,36,37,38四个GPIO口的电平状态,返回0或者1到主程序中,当35,36,38电平为高的时候,主程序的四个监控画面对应其中一个全屏显示;37脚外接控制台,长时间拉高,当控制台电源按钮关闭时,控制台会掩饰30s关闭,但是会将Pin37拉低,如果Pin37为低电平,开发板关机。python脚本程序如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | #!/usr/bin/env python import RPi.GPIO as GPIO import time #这里我用BOARD编码的方式定义引脚 input_pin = 37 left_pin = 35 right_pin = 36 back_pin = 38 def sleep_time(hour,min,sec): return hour *3600 + min * 60 +sec def left(): GPIO.setmode(GPIO.BOARD)#设置引脚为BOARD编码 try: while True: GPIO.setup(left_pin,GPIO.IN)#设置引脚为输入 value2 = GPIO.input(left_pin)#将该引脚的电平状态赋予value2 return value2#返回value2,在qt中调用时所需要用到的值 time.sleep(5) finally: GPIO.cleanup()#使用完后将引脚状态清零初始化 #下面的每个函数对应一个引脚,写法大同小异 def right(): GPIO.setmode(GPIO.BOARD) try: while True: GPIO.setup(right_pin,GPIO.IN) value3 = GPIO.input(right_pin) return value3 time.sleep(5) finally: GPIO.cleanup() def back(): GPIO.setmode(GPIO.BOARD) try: while True: GPIO.setup(back_pin,GPIO.IN) value4 = GPIO.input(back_pin) return value4 time.sleep(5) finally: GPIO.cleanup() def main(): prev_value = None GPIO.setmode(GPIO.BOARD) GPIO.setup(input_pin, GPIO.IN) try: while True: value1 = GPIO.input(input_pin) return value1 time.sleep(5) finally: GPIO.cleanup() if __name__ == '__main__': main() |
这里返回的value值,只有0和1,不会有电压大小
4.编写Qt程序
调用方法如下面的代码,头文件等忽略,只展示程序主体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | void MainWindow::GpioRead { while(true) { Py_Initialize();//初始化 if(!Py_IsInitialized()) { qDebug()<<"python init fail"; } else { qDebug()<<"python init sucess"; } //导入python需要使用的头文件 PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append('./')"); //将需要调用的python脚本打开,simple_input.py,不要写.py,写文件名即可 PyObject *pModule = PyImport_ImportModule("simple_input"); if(!pModule) { qDebug()<<"can not open file"; } else { qDebug()<<"open python file sucess"; } //调用打开的python脚本中的函数,这里调用的是main函数 PyObject *pFun = new PyObject; pFun = PyObject_GetAttrString(pModule,"main"); if(!pFun) { qDebug()<<"get fun fail"; } else { qDebug()<<"get fun sucess"; } PyObject *pCallBack = new PyObject; pCallBack = PyObject_CallFunction(pFun,NULL); //将调用main函数所得的返回值以int类型返回赋予pyResult int pyResult = 0; PyArg_Parse(pCallBack,"i",&pyResult); //如果返回值为0,即引脚电平为0,执行关机命令 if(pyResult == 0) { system("halt -p"); } //调用left函数,返回值赋予pyResultl PyObject *pleft = new PyObject; pleft = PyObject_GetAttrString(pModule,"left"); PyObject *pCallBackl = new PyObject; pCallBackl = PyObject_CallFunction(pleft,NULL); PyArg_Parse(pCallBackl,"i",&pyResultl); qDebug()<<"pyResultl = "<<pyResultl; //调用right函数,返回值赋予pyResultr PyObject *pright = new PyObject; pright = PyObject_GetAttrString(pModule,"right"); PyObject *pCallBackr = new PyObject; pCallBackr = PyObject_CallFunction(pright,NULL); PyArg_Parse(pCallBackr,"i",&pyResultr); qDebug()<<"pyResultr = "<<pyResultr; //调用back函数,返回值赋予pyResultb PyObject *pback = new PyObject; pback = PyObject_GetAttrString(pModule,"back"); PyObject *pCallBackb = new PyObject; pCallBackb = PyObject_CallFunction(pback,NULL); PyArg_Parse(pCallBackb,"i",&pyResultb); qDebug()<<"pyResultb = "<<pyResultb; //调用函数gpioFullBack,传入参数,当返回值为1时,对应的监控画面全屏,该函数后续贴出 gpioFullBack(pyResultl,pyResultr,pyResultb); Py_Finalize();//关闭python文件 sleep(5);//延时5s } } |
5.将Qt程序进行编译
编译Qt程序,先不要运行,编译通过后,将写好的python脚本文件放在编译的文件夹下。然后运行程序,亲测基本是没有问题的
四、补充
1、gpioFullBack函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | //一共有四个画面,对应前后左右,当倒车时,左转时,右转时,都有对应的画面全屏显示 void MainWindow::gpioFullBack(int pyResultFull,int pyResultFulll,int pyResultFullr) { int height = this->geometry().height() - this->ui->toolBar->height(); if(pyResultFull == 1) { QRect draw_rect(this->geometry().x(), this->geometry().y(), this->geometry().width(), height); ui->label_show_second_camera->resize(draw_rect.width(), draw_rect.height()); ui->label_show_second_camera->move(draw_rect.x(), draw_rect.y()); ui->label_show_first_caemra->hide(); ui->label_show_third_camera->hide(); ui->label_show_fourth_camera->hide(); } else if(pyResultFulll == 1) { QRect draw_rect(this->geometry().x(), this->geometry().y(), this->geometry().width(), height); ui->label_show_third_camera->resize(draw_rect.width(), draw_rect.height()); ui->label_show_third_camera->move(draw_rect.x(), draw_rect.y()); ui->label_show_first_caemra->hide(); ui->label_show_second_camera->hide(); ui->label_show_fourth_camera->hide(); } else if(pyResultFullr == 1) { QRect draw_rect(this->geometry().x(), this->geometry().y(), this->geometry().width(), height); ui->label_show_fourth_camera->resize(draw_rect.width(), draw_rect.height()); ui->label_show_fourth_camera->move(draw_rect.x(), draw_rect.y()); ui->label_show_first_caemra->hide(); ui->label_show_second_camera->hide(); ui->label_show_third_camera->hide(); } else { adjustItem(use_camera_); } } |
2.过程中遇到的问题
略,后续补充