这个工程是假期前完成的,延期更新了。
激光器的IO
所以说需要使用的是PWM,GPIO控制IO口,adc这三个知识点。
首先是要给设备加上pwm的驱动和adc的驱动。
pwm驱动 首先是imx6ull有8路PWM输出,对应这8个PWM的控制器,在设备树下有相对应的8个控制器节点。
查看手册可以看到:
• 16-bit up-counter with clock source selection • 4 x 16 FIFO to minimize interrupt overhead • 12-bit prescaler for division of clock • Sound and melody generation • Active high or active low configured output • Can be programmed to be active in low-power mode • Can be programmed to be active in debug mode • Interrupts at compare and rollover
使用GPIO1_IO04(也就是PWM3)来进行完成实验。在imx6ull.dtsi文件中已经有关于pwm3的节点信息了。
1 2 3 4 5 6 7 8 9 1 pwm3: pwm@02088000 { 2 compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm"; 3 reg = <0x02088000 0x4000>; 4 interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>; 5 clocks = <&clks IMX6UL_CLK_PWM3>, 6 <&clks IMX6UL_CLK_PWM3>; 7 clock-names = "ipg", "per"; 8 #pwm-cells = <2>; 9 };
在自己的设备树文件中进行追加GPIO1_IO04的信息。在iomuxc节点添加引脚信息。
1 2 3 4 5 pinctrl_pwm3: pwm3grp { fsl,pins = < MX6UL_PAD_GPIO1_IO04__PWM3_OUT 0x110b0 >; };
在根节点后的追加节点内容
1 2 3 4 5 6 7 &pwm3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm3>; clocks = <&clks IMX6UL_CLK_PWM3>, <&clks IMX6UL_CLK_PWM3>; status = "okay"; };
之后保存加载linux内核使能pwm驱动
1 2 3 -> Device Drivers -> Pulse-Width Modulation (PWM) Support -> <*> i.MX PWM support
之后打开设备通过串口查看根文件系统里的设备驱动加载。
1 2 3 $ cd /sys/class/pwm $ ls pwmchip0 pwmchip1 pwmchip2 pwmchip3 pwmchip4 pwmchip5 pwmchip6 pwmchip7
pwmchip0pwmchip7 对应 I.MX6ULL 的 PWM1PWM8,所以我们需要用到pwmchip2。
调出 pwmchip2 的 pwm0 子目录
1 echo 0 > /sys/class/pwm/pwmchip2/export
执行完成会在 pwmchip2 目录下生成一个名为“pwm0”的子目录 ,这个就是控制PWM3的目录
1 2 3 4 $cd pwm0 $echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable #使能pwm $echo 50000 > /sys/class/pwm/pwmchip2/pwm0/period #设置频率 $echo 10000 > /sys/class/pwm/pwmchip2/pwm0/duty_cycle #设置占空比
ADC驱动 使用的是IIO子系统框架来编写adc的传感器驱动,使用的是nxp编写好的ADC驱动,在其基础上添加引脚信息。
1 2 3 4 5 pinctrl_adc1: adc1grp { fsl,pins = < MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0 >; };
追加adc1节点
1 2 3 4 5 6 7 &adc1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_adc1>; num-channels = <2>; vref-supply = <®_vref_adc>; status = "okay"; };
使能内核自带的adc驱动
1 2 3 4 -> Device Drivers -> Industrial I/O support -> Analog to digital converters -> <*> Freescale vf610 ADC driver //选中
编译修改后的设备树,然后使用新的设备树启动系统。进入/sys/bus/iio/devices 目录下,此目录下就有 ADC 对应的 iio 设备: iio:deviceX
iio:device0”就是 ADC 设备,因为此时并没有加载其他的 IIO 设备驱动,只有一个 ADC。
in_voltage1_raw: ADC1 通道 1 原始值文件。 in_voltage_scale: ADC1 比例文件(分辨率),单位为 mV。实际电压值(mV)=in_voltage1_raw*in_voltage_scale
gpio的控制参考上一篇文章
最后就是通过QFile来操作文件,mainwindow.h文件如下
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 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QPushButton> #include <QSpinBox> #include <QLabel> #include <QProcess> #include <QFile> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow ; }QT_END_NAMESPACE class MainWindow : public QMainWindow{ Q_OBJECT public : MainWindow (QWidget *parent = nullptr ); ~MainWindow (); private : Ui::MainWindow *ui; QPushButton * start; QPushButton *update; QSpinBox * p_spinBox; QSpinBox *t_spinBox; QLabel *p_label; QLabel *t_label; QProcess *process; QFile file; QPushButton * uptemper; private slots: void pushButton_startprogress () ; void update_power () ; void up_temperature () ; }; #endif
mainwindow.cpp文件
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 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 #include "mainwindow.h" #include "ui_mainwindow.h" #include <QFile> #include <QString> #include <QDebug> #include <QProcess> int bytesToInt (QByteArray bytes) ;MainWindow::MainWindow (QWidget *parent) : QMainWindow (parent) , ui (new Ui::MainWindow) { ui->setupUi (this ); this ->setGeometry ( 0 , 0 , 800 , 480 ); start = new QPushButton ("开启激光器的配置" ,this ); start->setGeometry (100 , 100 , 120 , 40 ); update = new QPushButton ("控制功率" ,this ); update ->setGeometry (300 , 150 , 80 , 40 ); uptemper = new QPushButton ("更新温度功率的数据" ,this ); uptemper->setGeometry (300 , 190 , 160 , 40 ); file.setFileName ("/sys/bus/iio/devices/iio:device0/in_voltage0_raw" ); if (!file.exists ()){ QLabel * label = new QLabel ("文件不存在,无法调制功率" ,this ); label->setGeometry ( 270 , 100 , 200 , 40 ); } QLabel * label_p = new QLabel ("激光器功率为" ,this ); QLabel * label_t = new QLabel ("激光器温度为" ,this ); label_p -> setGeometry (100 , 150 , 100 , 40 ); label_t -> setGeometry (100 , 190 , 100 , 40 ); p_spinBox = new QSpinBox (this ); p_spinBox->setGeometry (210 , 150 , 60 , 40 ); p_spinBox->setRange (0 , 100 ); t_spinBox = new QSpinBox (this ); t_spinBox->setGeometry (210 , 190 , 60 , 40 ); connect (uptemper, SIGNAL (clicked ()), this , SLOT (up_temperature ())); connect (start, SIGNAL (clicked ()),this , SLOT (pushButton_startprogress ())); connect (update, SIGNAL (clicked ()),this , SLOT (update_power ())); } MainWindow::~MainWindow () { delete ui; } void MainWindow::pushButton_startprogress () { system ("echo 2 > /sys/class/gpio/export" ); system ("echo out > /sys/class/gpio/gpio2/direction" ); system ("echo 1 > /sys/class/gpio/gpio2/value" ); system ("echo 0 > /sys/class/gpio/export" ); system ("echo out > /sys/class/gpio/gpio0/direction" ); system ("echo 1 > /sys/class/gpio/gpio0/value" ); system ("echo 0 > /sys/class/pwm/pwmchip2/export" ); system ("echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable" ); system ("echo 50000 > /sys/class/pwm/pwmchip2/pwm0/period" ); system ("echo 10000 > /sys/class/pwm/pwmchip2/pwm0/duty_cycle" ); } void MainWindow::update_power () { int current_power = p_spinBox->value (); int a = current_power * 50000 / 100 ; qDebug () << a; QFile file1 ; file1.setFileName ("/sys/class/pwm/pwmchip2/pwm0/duty_cycle" ); if (!file1.exists ()) qDebug ()<<file.errorString (); if (!file1.open (QIODevice::ReadWrite)) qDebug ()<<file.errorString (); QString str = QString::number (a); file1.write (str.toUtf8 ()); } void MainWindow::up_temperature () { QFile file2 ; QFile file3 ; file2.setFileName ("/sys/bus/iio/devices/iio:device0/in_voltage1_raw" ); file3.setFileName ("/sys/bus/iio/devices/iio:device0/in_voltage_scale" ); bool isok2 = file2.open (QIODevice::ReadOnly); QByteArray array2; QByteArray array3; if (isok2 == true ) { array2 = file2.readAll (); } bool isok3 = file3.open (QIODevice::ReadOnly); if (isok3 == true ) { array3 = file3.readAll (); } double number = bytesToInt (array2) * bytesToInt (array3); t_spinBox ->setValue (number); } int bytesToInt (QByteArray bytes) { int addr = bytes[0 ] & 0x000000FF ; addr |= ((bytes[1 ] << 8 ) & 0x0000FF00 ); addr |= ((bytes[2 ] << 16 ) & 0x00FF0000 ); addr |= ((bytes[3 ] << 24 ) & 0xFF000000 ); return addr; }
结果如下,因为没有连接设备,在虚拟机上编译,所以没查到文件。这部分功能完成接下来就是光谱仪的开发了。