一、简介
1.实现功能
能够实时读取JetsonNano开发板GPIO口的电平信号,并将读到的电平信号返回到Qt主程序中
2.环境工具
开发板:JetsonNano
系统:Ubuntu
语言:C/C++,python
二、准备工作
1.JetsonNano开发板GPIO口介绍
JetsonNano的引脚与树莓派相似,有两种定义模式,一种是BCM编码,对应的是GPIO功能编码(图中Sysfs GPIO),一种是物理引脚编码,即BOARD编码(图中Pin)。
2.查看开发板是否预装了GPIO口的运行环境
cd /opt/nvidia/jetson-gpio
一般默认是安装好的,如果没有安装好,依次执行一下命令
安装pip工具
sudo apt-get update
sudo apt-get install python-pip
sudo apt-get install python3-pip
下载安装Jetson.GPIO库:
sudo pip install Jetson.GPIO
sudo pip3 install Jetson.GPIO
设置用户权限:
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控制等的简单例子,进入文件夹可查看
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保存一下,或者直接编译一下
2.在qt中加入头文件#include<python.h>
如果第一步没问题的话,#include<python.h>会自动补齐
3.根据自己的需要编写python脚本
我这里要实现的功能是实时读取35,36,37,38四个GPIO口的电平状态,返回0或者1到主程序中,当35,36,38电平为高的时候,主程序的四个监控画面对应其中一个全屏显示;37脚外接控制台,长时间拉高,当控制台电源按钮关闭时,控制台会掩饰30s关闭,但是会将Pin37拉低,如果Pin37为低电平,开发板关机。python脚本程序如下。
#!/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程序
调用方法如下面的代码,头文件等忽略,只展示程序主体
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函数
//一共有四个画面,对应前后左右,当倒车时,左转时,右转时,都有对应的画面全屏显示
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.过程中遇到的问题
略,后续补充