1. 实验思路
可以驱动的硬件有,3个按钮,RGB 小灯,需要通过按钮切换来实现这三个功能:
- 切换灯颜色:可以通过按钮指定灯的颜色
- 修改灯亮度:修改当前指定的灯的颜色的亮度
-
方案1
按钮1:增加当前颜色的分量
- 按钮2:减少当前颜色的分量
-
2. 硬件与插线
2.1 按键
按键已经在开发底板上连接,一端连接的引脚是KEY1,KEY2, KEY3,另外一端连接的都是GND
所以当按钮摁下的时候,变为低电平。
这时候我们需要把KEY1,KEY2,KEY3 和 旁边的 GPIO21 GPIO06 GPIO07 连接 GPIO21 —> KEY1
- GPIO07 —> KEY2
GPIO06 —> KEY3
2.2 三色灯
三色灯在电路板上已经连接上了树莓派:
GPIO29 —> LED_GREEN
- GPIO28 —> LED_RED
- GPIO27 —> LED_BLUE
三色灯的一端是GND,另外一端是上面对应的GPIO。将三色灯模块上的RGB对应连到地板上的LEDR,LEDG,LEDB,GND接地。

3. QT + WiringPi 基础
3.1 新建项目
3.2 加入wiringPi 支持
在.pro里面, 添加:
LIBS += -lwiringPi

在cpp文件的构造函数内,初始化它:
#include "mainwindow.h"#include "ui_mainwindow.h"#include "wiringPi.h" // 引入头文件MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow){ui->setupUi(this);wiringPiSetup(); // 初始化}
4. 关键模块
4.1 按键读取
4.1.1 思路
检测按下:用定时器读取对应key引脚的GPIO,若变为低电平说明按下
检测松开: 一直等待电压变回高电平
防抖: 检测到电平变了后, 等一段时间再检测一次
4.1.2 宏定义
在mainwindow.h 里面 为三个按钮的 GPIO 定义宏:
#define KEY1 21#define KEY2 07#define KEY3 06

4.1.3 相关api
pinmode():设置引脚模式为输入。pullUpDnControl():由于按下状态是低电平,要设置默认状态是高电平digitalRead():读取引脚电平delay():用于防抖的延时
4.1.4 初始化代码
初始化引脚模式并设置为高电平。因为按下接地是低电平,所以默认状态是高电平,需要通过pullUpDnControl来设置
// init pin of keyspinMode(KEY1, INPUT);pinMode(KEY2, INPUT);pinMode(KEY3, INPUT);// set defalut mode is highpullUpDnControl(KEY1, PUD_UP);pullUpDnControl(KEY2, PUD_UP);pullUpDnControl(KEY3, PUD_UP);
4.1.5 定义检查按键的函数
bool isClicked(int pin)
- 传入参数是要检测的引脚
- 传出参数是是否被按下
bool MainWindow::isClicked(int pin){if(digitalRead(pin) == 0){ // 0 是需要按下delay(100);// 防抖if(digitalRead(pin) == 0){while (digitalRead(pin) == 0);return true; // 返回的确是按下}}return false; // 返回没有是按下}
4.1.6 定时器执行的槽函数
/*mainwindows.h*/private slots:void ReadKey1();void ReadKey2();void ReadKey3();/*mainwindows.cpp*/void MainWindow::ReadKey1(){if(!isClicked(KEY1)){return;}qDebug() << "key1 clicked";}void MainWindow::ReadKey2(){if(!isClicked(KEY2)){return;}qDebug() << "key2 clicked";}void MainWindow::ReadKey3(){if(!isClicked(KEY3)){return;}qDebug() << "key3 clicked";}
4.1.7 定义并初始化定时器
/* mainwindows.h */public:QTimer *timer;/* mainwindows.cpp */timer = new QTimer;connect(timer, SIGNAL(timeout()), this, SLOT(ReadKey1));connect(timer, SIGNAL(timeout()), this, SLOT(ReadKey2));connect(timer, SIGNAL(timeout()), this, SLOT(ReadKey3));timer->start(50);
4.1.8 测试:
4.2. PWM控制小灯
4.2.1 思路
对于单个灯,控制它在一个周期内的占比,就可以控制亮度
例如:一个周期是1000us, 亮500us, 灭500us,就是50%的亮度
一个周期是1000us, 亮800us, 灭200us,就是80%的亮度
因此有2个关键参数
- 周期 :period
- 占空比:duty
周期确定了,调占空比就可以调亮度
因此可以基于wiringPi的softPwm,实现
4.2.2 宏定义
#define LED_R 28#define LED_G 29#define LED_B 27#define PERIOD 1000
4.2.3 用到的api
- softPwmCreate(int pin, int val , int ranger) 设置引脚是pwm模式,参数:
- 第一个参数是引脚
- 第二个参数是默认值
- 第三个参数是最可以设置的值
- softPwmWrite(int pin, int value)
4.2.5 控制亮度
这里只展示控制亮度的示例,具体和按键的结合会在下面给出
因为范围最大是100, 所以最大值给100
softPwmWrite(LED_R, 10);softPwmWrite(LED_G, 100);softPwmWrite(LED_R, 50);
5. 整体逻辑
使用一个now变量, 记录当前是哪个颜色
1 代表 红色
2 代表 绿色
3 代表 蓝色
初始值是1
5.1 颜色增加/ 减小槽函数
按钮1 是颜色增加的槽函数,首先判断当前是哪个按键,如果当前是4, 要跳回1
如果到最亮,啥都不干,不设置softPwm
void MainWindow::ReadKey1(){if(!isClicked(KEY1)){return;}qDebug() << "key1 clicked";// 如果now变成了4 说明要回到1if(now == 4) now =1;switch (now) {case 1:{if(red_value==100){break; // 到达最亮}red_value += 10;softPwmWrite(LED_R, red_value);break;}case 2:{if(green_value==100){break; // 到达最亮}green_value += 10;softPwmWrite(LED_G, green_value);break;}case 3:{if(blue_value==100){break; // 到达最亮}blue_value += 10;softPwmWrite(LED_B, blue_value);break;}}}
按钮2 是颜色减少的槽函数,首先判断当前是哪个按键,如果当前是4, 要跳回1
如果到最暗,啥都不干,不设置softPwm
void MainWindow::ReadKey2(){if(!isClicked(KEY2)){return;}qDebug() << "key2 clicked";qDebug() << "key1 clicked";if(now == 4) now = 1;switch (now) {case 1:{if(red_value==0){break;}red_value -= 10;softPwmWrite(LED_R, red_value);break;}case 2:{if(green_value==0){break;}green_value -= 10;softPwmWrite(LED_G, green_value);break;}case 3:{if(blue_value==0){break;}blue_value -= 10;softPwmWrite(LED_B, blue_value);break;}}}
5.3 确认槽函数
将 now + 1
void MainWindow::ReadKey3(){if(!isClicked(KEY3)){return;}qDebug() << "key3 clicked";now++;}
6. GUI绑定
思路1:
- 3个文本框, 可以设置和查看颜色分量
- 一个确定按钮,设置颜色
- 一个文本框,显示当前按钮的状态
7. 完整代码
头文件
#ifndef MAINWINDOW_H#define MAINWINDOW_H#define KEY1 21#define KEY2 07#define KEY3 06#define LED_R 28#define LED_G 29#define LED_B 27#define PERIOD 50#include <QMainWindow>#include <QTimer>namespace Ui {class MainWindow;}class MainWindow : public QMainWindow{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();QTimer *timer;QTimer *led_r_timer;QTimer *led_g_timer;QTimer *led_b_timer;private:Ui::MainWindow *ui;bool isClicked(int pin);int red_value;int blue_value;int green_value;int now;private slots:void ReadKey1();void ReadKey2();void ReadKey3();};#endif // MAINWINDOW_H
cpp 文件
#include "mainwindow.h"#include "ui_mainwindow.h"#include "wiringPi.h"#include "softPwm.h"#include <QDebug>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow){ui->setupUi(this);wiringPiSetup();// init pin of keyspinMode(KEY1, INPUT);pinMode(KEY2, INPUT);pinMode(KEY3, INPUT);// set defalut mode is highpullUpDnControl(KEY1, PUD_UP);pullUpDnControl(KEY2, PUD_UP);pullUpDnControl(KEY3, PUD_UP);// init pin of ledsoftPwmCreate(LED_R, 0, 100);softPwmCreate(LED_G, 0, 100);softPwmCreate(LED_B, 0, 100);//Init timertimer = new QTimer;connect(timer, SIGNAL(timeout()), this, SLOT(ReadKey1()));connect(timer, SIGNAL(timeout()), this, SLOT(ReadKey2()));connect(timer, SIGNAL(timeout()), this, SLOT(ReadKey3()));timer->start(50);red_value = 0;green_value = 0;blue_value = 0;now = 1;softPwmWrite(LED_R, 0);softPwmWrite(LED_G, 0);softPwmWrite(LED_B, 0);}MainWindow::~MainWindow(){delete ui;if(timer->isActive()){timer->stop();}delete timer;}bool MainWindow::isClicked(int pin){if(digitalRead(pin) == 0){delay(20);if(digitalRead(pin) == 0){while (digitalRead(pin) == 0);return true;}}return false;}void MainWindow::ReadKey1(){if(!isClicked(KEY1)){return;}qDebug() << "key1 clicked";if(now == 4) now =1;switch (now) {case 1:{if(red_value==100){break;}red_value += 10;softPwmWrite(LED_R, red_value);break;}case 2:{if(green_value==100){break;}green_value += 10;softPwmWrite(LED_G, green_value);break;}case 3:{if(blue_value==100){break;}blue_value += 10;softPwmWrite(LED_B, blue_value);break;}}}void MainWindow::ReadKey2(){if(!isClicked(KEY2)){return;}qDebug() << "key2 clicked";qDebug() << "key1 clicked";if(now == -1) now =3;switch (now) {case 1:{if(red_value==0){break;}red_value -= 10;softPwmWrite(LED_R, red_value);break;}case 2:{if(green_value==0){break;}green_value -= 10;softPwmWrite(LED_G, green_value);break;}case 3:{if(blue_value==0){break;}blue_value -= 10;softPwmWrite(LED_B, blue_value);break;}}}void MainWindow::ReadKey3(){if(!isClicked(KEY3)){return;}qDebug() << "key3 clicked";now++;}








