这个工程是假期前完成的,延期更新了。

激光器的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 = <&reg_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_H

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); //设置激光器功率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()));//开启激光器的IO口配置
connect(update, SIGNAL(clicked()),this, SLOT(update_power()));
}

MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::pushButton_startprogress()//初始化激光器完成
{
system("echo 2 > /sys/class/gpio/export"); //gpio1_02的IO口配置
system("echo out > /sys/class/gpio/gpio2/direction");
system("echo 1 > /sys/class/gpio/gpio2/value");

system("echo 0 > /sys/class/gpio/export"); //gpio1_00的IO口配置
system("echo out > /sys/class/gpio/gpio0/direction");
system("echo 1 > /sys/class/gpio/gpio0/value");

system("echo 0 > /sys/class/pwm/pwmchip2/export"); //使能pwm
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"); //选择占空比的文件
//file1.setFileName("/home/moss/test");
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"); //选择adc通道文件
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;
}

结果如下,因为没有连接设备,在虚拟机上编译,所以没查到文件。这部分功能完成接下来就是光谱仪的开发了。